diff options
Diffstat (limited to 'fs/xfs/xfs_dir2.c')
-rw-r--r-- | fs/xfs/xfs_dir2.c | 125 |
1 files changed, 107 insertions, 18 deletions
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index 7cb26529766b..80e0dc51361c 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c | |||
@@ -46,6 +46,54 @@ | |||
46 | 46 | ||
47 | struct xfs_name xfs_name_dotdot = {"..", 2}; | 47 | struct xfs_name xfs_name_dotdot = {"..", 2}; |
48 | 48 | ||
49 | extern const struct xfs_nameops xfs_default_nameops; | ||
50 | |||
51 | /* | ||
52 | * ASCII case-insensitive (ie. A-Z) support for directories that was | ||
53 | * used in IRIX. | ||
54 | */ | ||
55 | STATIC xfs_dahash_t | ||
56 | xfs_ascii_ci_hashname( | ||
57 | struct xfs_name *name) | ||
58 | { | ||
59 | xfs_dahash_t hash; | ||
60 | int i; | ||
61 | |||
62 | for (i = 0, hash = 0; i < name->len; i++) | ||
63 | hash = tolower(name->name[i]) ^ rol32(hash, 7); | ||
64 | |||
65 | return hash; | ||
66 | } | ||
67 | |||
68 | STATIC enum xfs_dacmp | ||
69 | xfs_ascii_ci_compname( | ||
70 | struct xfs_da_args *args, | ||
71 | const char *name, | ||
72 | int len) | ||
73 | { | ||
74 | enum xfs_dacmp result; | ||
75 | int i; | ||
76 | |||
77 | if (args->namelen != len) | ||
78 | return XFS_CMP_DIFFERENT; | ||
79 | |||
80 | result = XFS_CMP_EXACT; | ||
81 | for (i = 0; i < len; i++) { | ||
82 | if (args->name[i] == name[i]) | ||
83 | continue; | ||
84 | if (tolower(args->name[i]) != tolower(name[i])) | ||
85 | return XFS_CMP_DIFFERENT; | ||
86 | result = XFS_CMP_CASE; | ||
87 | } | ||
88 | |||
89 | return result; | ||
90 | } | ||
91 | |||
92 | static struct xfs_nameops xfs_ascii_ci_nameops = { | ||
93 | .hashname = xfs_ascii_ci_hashname, | ||
94 | .compname = xfs_ascii_ci_compname, | ||
95 | }; | ||
96 | |||
49 | void | 97 | void |
50 | xfs_dir_mount( | 98 | xfs_dir_mount( |
51 | xfs_mount_t *mp) | 99 | xfs_mount_t *mp) |
@@ -65,6 +113,10 @@ xfs_dir_mount( | |||
65 | (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) / | 113 | (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) / |
66 | (uint)sizeof(xfs_da_node_entry_t); | 114 | (uint)sizeof(xfs_da_node_entry_t); |
67 | mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100; | 115 | mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100; |
116 | if (xfs_sb_version_hasasciici(&mp->m_sb)) | ||
117 | mp->m_dirnameops = &xfs_ascii_ci_nameops; | ||
118 | else | ||
119 | mp->m_dirnameops = &xfs_default_nameops; | ||
68 | } | 120 | } |
69 | 121 | ||
70 | /* | 122 | /* |
@@ -162,9 +214,10 @@ xfs_dir_createname( | |||
162 | return rval; | 214 | return rval; |
163 | XFS_STATS_INC(xs_dir_create); | 215 | XFS_STATS_INC(xs_dir_create); |
164 | 216 | ||
217 | memset(&args, 0, sizeof(xfs_da_args_t)); | ||
165 | args.name = name->name; | 218 | args.name = name->name; |
166 | args.namelen = name->len; | 219 | args.namelen = name->len; |
167 | args.hashval = xfs_da_hashname(name->name, name->len); | 220 | args.hashval = dp->i_mount->m_dirnameops->hashname(name); |
168 | args.inumber = inum; | 221 | args.inumber = inum; |
169 | args.dp = dp; | 222 | args.dp = dp; |
170 | args.firstblock = first; | 223 | args.firstblock = first; |
@@ -172,8 +225,7 @@ xfs_dir_createname( | |||
172 | args.total = total; | 225 | args.total = total; |
173 | args.whichfork = XFS_DATA_FORK; | 226 | args.whichfork = XFS_DATA_FORK; |
174 | args.trans = tp; | 227 | args.trans = tp; |
175 | args.justcheck = 0; | 228 | args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; |
176 | args.addname = args.oknoent = 1; | ||
177 | 229 | ||
178 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 230 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
179 | rval = xfs_dir2_sf_addname(&args); | 231 | rval = xfs_dir2_sf_addname(&args); |
@@ -191,14 +243,43 @@ xfs_dir_createname( | |||
191 | } | 243 | } |
192 | 244 | ||
193 | /* | 245 | /* |
246 | * If doing a CI lookup and case-insensitive match, dup actual name into | ||
247 | * args.value. Return EEXIST for success (ie. name found) or an error. | ||
248 | */ | ||
249 | int | ||
250 | xfs_dir_cilookup_result( | ||
251 | struct xfs_da_args *args, | ||
252 | const char *name, | ||
253 | int len) | ||
254 | { | ||
255 | if (args->cmpresult == XFS_CMP_DIFFERENT) | ||
256 | return ENOENT; | ||
257 | if (args->cmpresult != XFS_CMP_CASE || | ||
258 | !(args->op_flags & XFS_DA_OP_CILOOKUP)) | ||
259 | return EEXIST; | ||
260 | |||
261 | args->value = kmem_alloc(len, KM_MAYFAIL); | ||
262 | if (!args->value) | ||
263 | return ENOMEM; | ||
264 | |||
265 | memcpy(args->value, name, len); | ||
266 | args->valuelen = len; | ||
267 | return EEXIST; | ||
268 | } | ||
269 | |||
270 | /* | ||
194 | * Lookup a name in a directory, give back the inode number. | 271 | * Lookup a name in a directory, give back the inode number. |
272 | * If ci_name is not NULL, returns the actual name in ci_name if it differs | ||
273 | * to name, or ci_name->name is set to NULL for an exact match. | ||
195 | */ | 274 | */ |
275 | |||
196 | int | 276 | int |
197 | xfs_dir_lookup( | 277 | xfs_dir_lookup( |
198 | xfs_trans_t *tp, | 278 | xfs_trans_t *tp, |
199 | xfs_inode_t *dp, | 279 | xfs_inode_t *dp, |
200 | struct xfs_name *name, | 280 | struct xfs_name *name, |
201 | xfs_ino_t *inum) /* out: inode number */ | 281 | xfs_ino_t *inum, /* out: inode number */ |
282 | struct xfs_name *ci_name) /* out: actual name if CI match */ | ||
202 | { | 283 | { |
203 | xfs_da_args_t args; | 284 | xfs_da_args_t args; |
204 | int rval; | 285 | int rval; |
@@ -206,15 +287,17 @@ xfs_dir_lookup( | |||
206 | 287 | ||
207 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 288 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); |
208 | XFS_STATS_INC(xs_dir_lookup); | 289 | XFS_STATS_INC(xs_dir_lookup); |
209 | memset(&args, 0, sizeof(xfs_da_args_t)); | ||
210 | 290 | ||
291 | memset(&args, 0, sizeof(xfs_da_args_t)); | ||
211 | args.name = name->name; | 292 | args.name = name->name; |
212 | args.namelen = name->len; | 293 | args.namelen = name->len; |
213 | args.hashval = xfs_da_hashname(name->name, name->len); | 294 | args.hashval = dp->i_mount->m_dirnameops->hashname(name); |
214 | args.dp = dp; | 295 | args.dp = dp; |
215 | args.whichfork = XFS_DATA_FORK; | 296 | args.whichfork = XFS_DATA_FORK; |
216 | args.trans = tp; | 297 | args.trans = tp; |
217 | args.oknoent = 1; | 298 | args.op_flags = XFS_DA_OP_OKNOENT; |
299 | if (ci_name) | ||
300 | args.op_flags |= XFS_DA_OP_CILOOKUP; | ||
218 | 301 | ||
219 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 302 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
220 | rval = xfs_dir2_sf_lookup(&args); | 303 | rval = xfs_dir2_sf_lookup(&args); |
@@ -230,8 +313,13 @@ xfs_dir_lookup( | |||
230 | rval = xfs_dir2_node_lookup(&args); | 313 | rval = xfs_dir2_node_lookup(&args); |
231 | if (rval == EEXIST) | 314 | if (rval == EEXIST) |
232 | rval = 0; | 315 | rval = 0; |
233 | if (rval == 0) | 316 | if (!rval) { |
234 | *inum = args.inumber; | 317 | *inum = args.inumber; |
318 | if (ci_name) { | ||
319 | ci_name->name = args.value; | ||
320 | ci_name->len = args.valuelen; | ||
321 | } | ||
322 | } | ||
235 | return rval; | 323 | return rval; |
236 | } | 324 | } |
237 | 325 | ||
@@ -255,9 +343,10 @@ xfs_dir_removename( | |||
255 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 343 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); |
256 | XFS_STATS_INC(xs_dir_remove); | 344 | XFS_STATS_INC(xs_dir_remove); |
257 | 345 | ||
346 | memset(&args, 0, sizeof(xfs_da_args_t)); | ||
258 | args.name = name->name; | 347 | args.name = name->name; |
259 | args.namelen = name->len; | 348 | args.namelen = name->len; |
260 | args.hashval = xfs_da_hashname(name->name, name->len); | 349 | args.hashval = dp->i_mount->m_dirnameops->hashname(name); |
261 | args.inumber = ino; | 350 | args.inumber = ino; |
262 | args.dp = dp; | 351 | args.dp = dp; |
263 | args.firstblock = first; | 352 | args.firstblock = first; |
@@ -265,7 +354,6 @@ xfs_dir_removename( | |||
265 | args.total = total; | 354 | args.total = total; |
266 | args.whichfork = XFS_DATA_FORK; | 355 | args.whichfork = XFS_DATA_FORK; |
267 | args.trans = tp; | 356 | args.trans = tp; |
268 | args.justcheck = args.addname = args.oknoent = 0; | ||
269 | 357 | ||
270 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 358 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
271 | rval = xfs_dir2_sf_removename(&args); | 359 | rval = xfs_dir2_sf_removename(&args); |
@@ -338,9 +426,10 @@ xfs_dir_replace( | |||
338 | if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) | 426 | if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) |
339 | return rval; | 427 | return rval; |
340 | 428 | ||
429 | memset(&args, 0, sizeof(xfs_da_args_t)); | ||
341 | args.name = name->name; | 430 | args.name = name->name; |
342 | args.namelen = name->len; | 431 | args.namelen = name->len; |
343 | args.hashval = xfs_da_hashname(name->name, name->len); | 432 | args.hashval = dp->i_mount->m_dirnameops->hashname(name); |
344 | args.inumber = inum; | 433 | args.inumber = inum; |
345 | args.dp = dp; | 434 | args.dp = dp; |
346 | args.firstblock = first; | 435 | args.firstblock = first; |
@@ -348,7 +437,6 @@ xfs_dir_replace( | |||
348 | args.total = total; | 437 | args.total = total; |
349 | args.whichfork = XFS_DATA_FORK; | 438 | args.whichfork = XFS_DATA_FORK; |
350 | args.trans = tp; | 439 | args.trans = tp; |
351 | args.justcheck = args.addname = args.oknoent = 0; | ||
352 | 440 | ||
353 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 441 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
354 | rval = xfs_dir2_sf_replace(&args); | 442 | rval = xfs_dir2_sf_replace(&args); |
@@ -384,15 +472,16 @@ xfs_dir_canenter( | |||
384 | return 0; | 472 | return 0; |
385 | 473 | ||
386 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 474 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); |
387 | memset(&args, 0, sizeof(xfs_da_args_t)); | ||
388 | 475 | ||
476 | memset(&args, 0, sizeof(xfs_da_args_t)); | ||
389 | args.name = name->name; | 477 | args.name = name->name; |
390 | args.namelen = name->len; | 478 | args.namelen = name->len; |
391 | args.hashval = xfs_da_hashname(name->name, name->len); | 479 | args.hashval = dp->i_mount->m_dirnameops->hashname(name); |
392 | args.dp = dp; | 480 | args.dp = dp; |
393 | args.whichfork = XFS_DATA_FORK; | 481 | args.whichfork = XFS_DATA_FORK; |
394 | args.trans = tp; | 482 | args.trans = tp; |
395 | args.justcheck = args.addname = args.oknoent = 1; | 483 | args.op_flags = XFS_DA_OP_JUSTCHECK | XFS_DA_OP_ADDNAME | |
484 | XFS_DA_OP_OKNOENT; | ||
396 | 485 | ||
397 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 486 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
398 | rval = xfs_dir2_sf_addname(&args); | 487 | rval = xfs_dir2_sf_addname(&args); |
@@ -493,7 +582,7 @@ xfs_dir2_grow_inode( | |||
493 | args->firstblock, args->total, | 582 | args->firstblock, args->total, |
494 | &mapp[mapi], &nmap, args->flist, | 583 | &mapp[mapi], &nmap, args->flist, |
495 | NULL))) { | 584 | NULL))) { |
496 | kmem_free(mapp, sizeof(*mapp) * count); | 585 | kmem_free(mapp); |
497 | return error; | 586 | return error; |
498 | } | 587 | } |
499 | if (nmap < 1) | 588 | if (nmap < 1) |
@@ -525,14 +614,14 @@ xfs_dir2_grow_inode( | |||
525 | mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != | 614 | mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != |
526 | bno + count) { | 615 | bno + count) { |
527 | if (mapp != &map) | 616 | if (mapp != &map) |
528 | kmem_free(mapp, sizeof(*mapp) * count); | 617 | kmem_free(mapp); |
529 | return XFS_ERROR(ENOSPC); | 618 | return XFS_ERROR(ENOSPC); |
530 | } | 619 | } |
531 | /* | 620 | /* |
532 | * Done with the temporary mapping table. | 621 | * Done with the temporary mapping table. |
533 | */ | 622 | */ |
534 | if (mapp != &map) | 623 | if (mapp != &map) |
535 | kmem_free(mapp, sizeof(*mapp) * count); | 624 | kmem_free(mapp); |
536 | *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno); | 625 | *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno); |
537 | /* | 626 | /* |
538 | * Update file's size if this is the data space and it grew. | 627 | * Update file's size if this is the data space and it grew. |