1300 filename normalization doesn't work for removes
illumos/illumos-gate@1c17160ac5
1c17160ac5
https://www.illumos.org/issues/1300
Problem:
We can create invisible file in ZFS.
How to reproduce:
0. Prepare normalization formD ZFS.
# cat cat /etc/release
cat: cat: No such file or directory
OpenIndiana Development oi_151 X86 (powered by illumos)
Copyright 2011 Oracle and/or its affiliates. All rights reserved.
Use is subject to license terms.
Assembled 28 April 2011
# mkfile 100M 100M
# zpool create -O utf8only=on -O normalization=formD test_pool $( pwd )/
100M
# zpool upgrade
This system is currently running ZFS pool version 28.
All pools are formatted using this version.
# zfs get normalization test_pool
NAME PROPERTY VALUE SOURCE
test_pool normalization formD -
# chmod 777 /test_pool
1. Create a NFD file.
$ cd /test_pool/
$ cp /etc/release $( echo "\x75\xcc\x88" )
$ ls -la
total 4
drwxrwxrwx 2 root root 3 2011-07-29 08:53 .
drwxr-xr-x 25 root root 26 2011-07-29 08:53 ..
-r--r--r-- 1 test1 staff 251 2011-07-29 08:53 u?
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Pavel Zakharov <pavel.zakharov@delphix.com>
Reviewed by: Matt Ahrens <mahrens@delphix.com>
Approved by: Dan McDonald <danmcd@omniti.com>
Author: Kevin Crowe <kevin.crowe@nexenta.com>
This commit is contained in:
parent
be49e7b29b
commit
b71204d77d
@ -18,15 +18,16 @@
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
|
||||
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2015, STRATO AG, Inc. All rights reserved.
|
||||
* Copyright (c) 2014 Integros [integros.com]
|
||||
* Copyright 2017 Nexenta Systems, Inc.
|
||||
*/
|
||||
|
||||
/* Portions Copyright 2010 Robert Milkowski */
|
||||
@ -1622,7 +1623,7 @@ dmu_snapshot_realname(objset_t *os, char *name, char *real, int maxlen,
|
||||
|
||||
return (zap_lookup_norm(ds->ds_dir->dd_pool->dp_meta_objset,
|
||||
dsl_dataset_phys(ds)->ds_snapnames_zapobj, name, 8, 1, &ignored,
|
||||
MT_FIRST, real, maxlen, conflict));
|
||||
MT_NORMALIZE, real, maxlen, conflict));
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -12,8 +12,10 @@
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013, 2014 by Delphix. All rights reserved.
|
||||
* Copyright 2017 Nexenta Systems, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
@ -59,16 +61,14 @@ dsl_dataset_bmark_lookup(dsl_dataset_t *ds, const char *shortname,
|
||||
{
|
||||
objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
|
||||
uint64_t bmark_zapobj = ds->ds_bookmarks;
|
||||
matchtype_t mt;
|
||||
matchtype_t mt = 0;
|
||||
int err;
|
||||
|
||||
if (bmark_zapobj == 0)
|
||||
return (SET_ERROR(ESRCH));
|
||||
|
||||
if (dsl_dataset_phys(ds)->ds_flags & DS_FLAG_CI_DATASET)
|
||||
mt = MT_FIRST;
|
||||
else
|
||||
mt = MT_EXACT;
|
||||
mt = MT_NORMALIZE;
|
||||
|
||||
err = zap_lookup_norm(mos, bmark_zapobj, shortname, sizeof (uint64_t),
|
||||
sizeof (*bmark_phys) / sizeof (uint64_t), bmark_phys, mt,
|
||||
@ -339,12 +339,10 @@ dsl_dataset_bookmark_remove(dsl_dataset_t *ds, const char *name, dmu_tx_t *tx)
|
||||
{
|
||||
objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
|
||||
uint64_t bmark_zapobj = ds->ds_bookmarks;
|
||||
matchtype_t mt;
|
||||
matchtype_t mt = 0;
|
||||
|
||||
if (dsl_dataset_phys(ds)->ds_flags & DS_FLAG_CI_DATASET)
|
||||
mt = MT_FIRST;
|
||||
else
|
||||
mt = MT_EXACT;
|
||||
mt = MT_NORMALIZE;
|
||||
|
||||
return (zap_remove_norm(mos, bmark_zapobj, name, mt, tx));
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2016 by Delphix. All rights reserved.
|
||||
@ -26,6 +27,7 @@
|
||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||
* Copyright (c) 2014 Integros [integros.com]
|
||||
* Copyright 2016, OmniTI Computer Consulting, Inc. All rights reserved.
|
||||
* Copyright 2017 Nexenta Systems, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/dmu_objset.h>
|
||||
@ -353,17 +355,15 @@ dsl_dataset_snap_lookup(dsl_dataset_t *ds, const char *name, uint64_t *value)
|
||||
{
|
||||
objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
|
||||
uint64_t snapobj = dsl_dataset_phys(ds)->ds_snapnames_zapobj;
|
||||
matchtype_t mt;
|
||||
matchtype_t mt = 0;
|
||||
int err;
|
||||
|
||||
if (dsl_dataset_phys(ds)->ds_flags & DS_FLAG_CI_DATASET)
|
||||
mt = MT_FIRST;
|
||||
else
|
||||
mt = MT_EXACT;
|
||||
mt = MT_NORMALIZE;
|
||||
|
||||
err = zap_lookup_norm(mos, snapobj, name, 8, 1,
|
||||
value, mt, NULL, 0, NULL);
|
||||
if (err == ENOTSUP && mt == MT_FIRST)
|
||||
if (err == ENOTSUP && (mt & MT_NORMALIZE))
|
||||
err = zap_lookup(mos, snapobj, name, 8, 1, value);
|
||||
return (err);
|
||||
}
|
||||
@ -374,18 +374,16 @@ dsl_dataset_snap_remove(dsl_dataset_t *ds, const char *name, dmu_tx_t *tx,
|
||||
{
|
||||
objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
|
||||
uint64_t snapobj = dsl_dataset_phys(ds)->ds_snapnames_zapobj;
|
||||
matchtype_t mt;
|
||||
matchtype_t mt = 0;
|
||||
int err;
|
||||
|
||||
dsl_dir_snap_cmtime_update(ds->ds_dir);
|
||||
|
||||
if (dsl_dataset_phys(ds)->ds_flags & DS_FLAG_CI_DATASET)
|
||||
mt = MT_FIRST;
|
||||
else
|
||||
mt = MT_EXACT;
|
||||
mt = MT_NORMALIZE;
|
||||
|
||||
err = zap_remove_norm(mos, snapobj, name, mt, tx);
|
||||
if (err == ENOTSUP && mt == MT_FIRST)
|
||||
if (err == ENOTSUP && (mt & MT_NORMALIZE))
|
||||
err = zap_remove(mos, snapobj, name, tx);
|
||||
|
||||
if (err == 0 && adj_cnt)
|
||||
|
@ -18,9 +18,11 @@
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
|
||||
* Copyright 2017 Nexenta Systems, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_ZAP_H
|
||||
@ -88,22 +90,15 @@ extern "C" {
|
||||
|
||||
/*
|
||||
* Specifies matching criteria for ZAP lookups.
|
||||
* MT_NORMALIZE Use ZAP normalization flags, which can include both
|
||||
* unicode normalization and case-insensitivity.
|
||||
* MT_MATCH_CASE Do case-sensitive lookups even if MT_NORMALIZE is
|
||||
* specified and ZAP normalization flags include
|
||||
* U8_TEXTPREP_TOUPPER.
|
||||
*/
|
||||
typedef enum matchtype
|
||||
{
|
||||
/* Only find an exact match (non-normalized) */
|
||||
MT_EXACT,
|
||||
/*
|
||||
* If there is an exact match, find that, otherwise find the
|
||||
* first normalized match.
|
||||
*/
|
||||
MT_BEST,
|
||||
/*
|
||||
* Find the "first" normalized (case and Unicode form) match;
|
||||
* the designated "first" match will not change as long as the
|
||||
* set of entries with this normalization doesn't change.
|
||||
*/
|
||||
MT_FIRST
|
||||
typedef enum matchtype {
|
||||
MT_NORMALIZE = 1 << 0,
|
||||
MT_MATCH_CASE = 1 << 1,
|
||||
} matchtype_t;
|
||||
|
||||
typedef enum zap_flags {
|
||||
@ -120,16 +115,6 @@ typedef enum zap_flags {
|
||||
|
||||
/*
|
||||
* Create a new zapobj with no attributes and return its object number.
|
||||
* MT_EXACT will cause the zap object to only support MT_EXACT lookups,
|
||||
* otherwise any matchtype can be used for lookups.
|
||||
*
|
||||
* normflags specifies what normalization will be done. values are:
|
||||
* 0: no normalization (legacy on-disk format, supports MT_EXACT matching
|
||||
* only)
|
||||
* U8_TEXTPREP_TOLOWER: case normalization will be performed.
|
||||
* MT_FIRST/MT_BEST matching will find entries that match without
|
||||
* regard to case (eg. looking for "foo" can find an entry "Foo").
|
||||
* Eventually, other flags will permit unicode normalization as well.
|
||||
*/
|
||||
uint64_t zap_create(objset_t *ds, dmu_object_type_t ot,
|
||||
dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
|
||||
|
@ -18,11 +18,13 @@
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2016 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||
* Copyright (c) 2014 Integros [integros.com]
|
||||
* Copyright 2017 Nexenta Systems, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_ZAP_IMPL_H
|
||||
@ -189,6 +191,7 @@ typedef struct zap_name {
|
||||
int zn_key_norm_numints;
|
||||
uint64_t zn_hash;
|
||||
matchtype_t zn_matchtype;
|
||||
int zn_normflags;
|
||||
char zn_normbuf[ZAP_MAXNAMELEN];
|
||||
} zap_name_t;
|
||||
|
||||
|
@ -18,9 +18,11 @@
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2015 by Delphix. All rights reserved.
|
||||
* Copyright 2017 Nexenta Systems, Inc.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -361,7 +363,7 @@ zap_leaf_array_match(zap_leaf_t *l, zap_name_t *zn,
|
||||
}
|
||||
|
||||
ASSERT(zn->zn_key_intlen == 1);
|
||||
if (zn->zn_matchtype == MT_FIRST) {
|
||||
if (zn->zn_matchtype & MT_NORMALIZE) {
|
||||
char *thisname = kmem_alloc(array_numints, KM_SLEEP);
|
||||
boolean_t match;
|
||||
|
||||
@ -403,7 +405,6 @@ zap_leaf_lookup(zap_leaf_t *l, zap_name_t *zn, zap_entry_handle_t *zeh)
|
||||
|
||||
ASSERT3U(zap_leaf_phys(l)->l_hdr.lh_magic, ==, ZAP_LEAF_MAGIC);
|
||||
|
||||
again:
|
||||
for (chunkp = LEAF_HASH_ENTPTR(l, zn->zn_hash);
|
||||
*chunkp != CHAIN_END; chunkp = &le->le_next) {
|
||||
uint16_t chunk = *chunkp;
|
||||
@ -418,9 +419,9 @@ zap_leaf_lookup(zap_leaf_t *l, zap_name_t *zn, zap_entry_handle_t *zeh)
|
||||
/*
|
||||
* NB: the entry chain is always sorted by cd on
|
||||
* normalized zap objects, so this will find the
|
||||
* lowest-cd match for MT_FIRST.
|
||||
* lowest-cd match for MT_NORMALIZE.
|
||||
*/
|
||||
ASSERT(zn->zn_matchtype == MT_EXACT ||
|
||||
ASSERT((zn->zn_matchtype == 0) ||
|
||||
(zap_leaf_phys(l)->l_hdr.lh_flags & ZLF_ENTRIES_CDSORTED));
|
||||
if (zap_leaf_array_match(l, zn, le->le_name_chunk,
|
||||
le->le_name_numints)) {
|
||||
@ -434,15 +435,6 @@ zap_leaf_lookup(zap_leaf_t *l, zap_name_t *zn, zap_entry_handle_t *zeh)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NB: we could of course do this in one pass, but that would be
|
||||
* a pain. We'll see if MT_BEST is even used much.
|
||||
*/
|
||||
if (zn->zn_matchtype == MT_BEST) {
|
||||
zn->zn_matchtype = MT_FIRST;
|
||||
goto again;
|
||||
}
|
||||
|
||||
return (SET_ERROR(ENOENT));
|
||||
}
|
||||
|
||||
@ -697,7 +689,7 @@ zap_entry_normalization_conflict(zap_entry_handle_t *zeh, zap_name_t *zn,
|
||||
continue;
|
||||
|
||||
if (zn == NULL) {
|
||||
zn = zap_name_alloc(zap, name, MT_FIRST);
|
||||
zn = zap_name_alloc(zap, name, MT_NORMALIZE);
|
||||
allocdzn = B_TRUE;
|
||||
}
|
||||
if (zap_leaf_array_match(zeh->zeh_leaf, zn,
|
||||
|
@ -18,11 +18,13 @@
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2016 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||
* Copyright (c) 2014 Integros [integros.com]
|
||||
* Copyright 2017 Nexenta Systems, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/zio.h>
|
||||
@ -133,7 +135,7 @@ zap_hash(zap_name_t *zn)
|
||||
}
|
||||
|
||||
static int
|
||||
zap_normalize(zap_t *zap, const char *name, char *namenorm)
|
||||
zap_normalize(zap_t *zap, const char *name, char *namenorm, int normflags)
|
||||
{
|
||||
size_t inlen, outlen;
|
||||
int err;
|
||||
@ -145,8 +147,8 @@ zap_normalize(zap_t *zap, const char *name, char *namenorm)
|
||||
|
||||
err = 0;
|
||||
(void) u8_textprep_str((char *)name, &inlen, namenorm, &outlen,
|
||||
zap->zap_normflags | U8_TEXTPREP_IGNORE_NULL |
|
||||
U8_TEXTPREP_IGNORE_INVALID, U8_UNICODE_LATEST, &err);
|
||||
normflags | U8_TEXTPREP_IGNORE_NULL | U8_TEXTPREP_IGNORE_INVALID,
|
||||
U8_UNICODE_LATEST, &err);
|
||||
|
||||
return (err);
|
||||
}
|
||||
@ -156,15 +158,15 @@ zap_match(zap_name_t *zn, const char *matchname)
|
||||
{
|
||||
ASSERT(!(zap_getflags(zn->zn_zap) & ZAP_FLAG_UINT64_KEY));
|
||||
|
||||
if (zn->zn_matchtype == MT_FIRST) {
|
||||
if (zn->zn_matchtype & MT_NORMALIZE) {
|
||||
char norm[ZAP_MAXNAMELEN];
|
||||
|
||||
if (zap_normalize(zn->zn_zap, matchname, norm) != 0)
|
||||
if (zap_normalize(zn->zn_zap, matchname, norm,
|
||||
zn->zn_normflags) != 0)
|
||||
return (B_FALSE);
|
||||
|
||||
return (strcmp(zn->zn_key_norm, norm) == 0);
|
||||
} else {
|
||||
/* MT_BEST or MT_EXACT */
|
||||
return (strcmp(zn->zn_key_orig, matchname) == 0);
|
||||
}
|
||||
}
|
||||
@ -185,15 +187,30 @@ zap_name_alloc(zap_t *zap, const char *key, matchtype_t mt)
|
||||
zn->zn_key_orig = key;
|
||||
zn->zn_key_orig_numints = strlen(zn->zn_key_orig) + 1;
|
||||
zn->zn_matchtype = mt;
|
||||
zn->zn_normflags = zap->zap_normflags;
|
||||
|
||||
/*
|
||||
* If we're dealing with a case sensitive lookup on a mixed or
|
||||
* insensitive fs, remove U8_TEXTPREP_TOUPPER or the lookup
|
||||
* will fold case to all caps overriding the lookup request.
|
||||
*/
|
||||
if (mt & MT_MATCH_CASE)
|
||||
zn->zn_normflags &= ~U8_TEXTPREP_TOUPPER;
|
||||
|
||||
if (zap->zap_normflags) {
|
||||
if (zap_normalize(zap, key, zn->zn_normbuf) != 0) {
|
||||
/*
|
||||
* We *must* use zap_normflags because this normalization is
|
||||
* what the hash is computed from.
|
||||
*/
|
||||
if (zap_normalize(zap, key, zn->zn_normbuf,
|
||||
zap->zap_normflags) != 0) {
|
||||
zap_name_free(zn);
|
||||
return (NULL);
|
||||
}
|
||||
zn->zn_key_norm = zn->zn_normbuf;
|
||||
zn->zn_key_norm_numints = strlen(zn->zn_key_norm) + 1;
|
||||
} else {
|
||||
if (mt != MT_EXACT) {
|
||||
if (mt != 0) {
|
||||
zap_name_free(zn);
|
||||
return (NULL);
|
||||
}
|
||||
@ -202,6 +219,20 @@ zap_name_alloc(zap_t *zap, const char *key, matchtype_t mt)
|
||||
}
|
||||
|
||||
zn->zn_hash = zap_hash(zn);
|
||||
|
||||
if (zap->zap_normflags != zn->zn_normflags) {
|
||||
/*
|
||||
* We *must* use zn_normflags because this normalization is
|
||||
* what the matching is based on. (Not the hash!)
|
||||
*/
|
||||
if (zap_normalize(zap, key, zn->zn_normbuf,
|
||||
zn->zn_normflags) != 0) {
|
||||
zap_name_free(zn);
|
||||
return (NULL);
|
||||
}
|
||||
zn->zn_key_norm_numints = strlen(zn->zn_key_norm) + 1;
|
||||
}
|
||||
|
||||
return (zn);
|
||||
}
|
||||
|
||||
@ -215,7 +246,7 @@ zap_name_alloc_uint64(zap_t *zap, const uint64_t *key, int numints)
|
||||
zn->zn_key_intlen = sizeof (*key);
|
||||
zn->zn_key_orig = zn->zn_key_norm = key;
|
||||
zn->zn_key_orig_numints = zn->zn_key_norm_numints = numints;
|
||||
zn->zn_matchtype = MT_EXACT;
|
||||
zn->zn_matchtype = 0;
|
||||
|
||||
zn->zn_hash = zap_hash(zn);
|
||||
return (zn);
|
||||
@ -299,7 +330,6 @@ mze_find(zap_name_t *zn)
|
||||
mze_tofind.mze_hash = zn->zn_hash;
|
||||
mze_tofind.mze_cd = 0;
|
||||
|
||||
again:
|
||||
mze = avl_find(avl, &mze_tofind, &idx);
|
||||
if (mze == NULL)
|
||||
mze = avl_nearest(avl, idx, AVL_AFTER);
|
||||
@ -308,10 +338,7 @@ mze_find(zap_name_t *zn)
|
||||
if (zap_match(zn, MZE_PHYS(zn->zn_zap, mze)->mze_name))
|
||||
return (mze);
|
||||
}
|
||||
if (zn->zn_matchtype == MT_BEST) {
|
||||
zn->zn_matchtype = MT_FIRST;
|
||||
goto again;
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
@ -417,8 +444,7 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
|
||||
zap_name_t *zn;
|
||||
|
||||
zap->zap_m.zap_num_entries++;
|
||||
zn = zap_name_alloc(zap, mze->mze_name,
|
||||
MT_EXACT);
|
||||
zn = zap_name_alloc(zap, mze->mze_name, 0);
|
||||
mze_insert(zap, i, zn->zn_hash);
|
||||
zap_name_free(zn);
|
||||
}
|
||||
@ -618,7 +644,7 @@ mzap_upgrade(zap_t **zapp, void *tag, dmu_tx_t *tx, zap_flags_t flags)
|
||||
continue;
|
||||
dprintf("adding %s=%llu\n",
|
||||
mze->mze_name, mze->mze_value);
|
||||
zn = zap_name_alloc(zap, mze->mze_name, MT_EXACT);
|
||||
zn = zap_name_alloc(zap, mze->mze_name, 0);
|
||||
err = fzap_add_cd(zn, 8, 1, &mze->mze_value, mze->mze_cd,
|
||||
tag, tx);
|
||||
zap = zn->zn_zap; /* fzap_add_cd() may change zap */
|
||||
@ -631,6 +657,23 @@ mzap_upgrade(zap_t **zapp, void *tag, dmu_tx_t *tx, zap_flags_t flags)
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* The "normflags" determine the behavior of the matchtype_t which is
|
||||
* passed to zap_lookup_norm(). Names which have the same normalized
|
||||
* version will be stored with the same hash value, and therefore we can
|
||||
* perform normalization-insensitive lookups. We can be Unicode form-
|
||||
* insensitive and/or case-insensitive. The following flags are valid for
|
||||
* "normflags":
|
||||
*
|
||||
* U8_TEXTPREP_NFC
|
||||
* U8_TEXTPREP_NFD
|
||||
* U8_TEXTPREP_NFKC
|
||||
* U8_TEXTPREP_NFKD
|
||||
* U8_TEXTPREP_TOUPPER
|
||||
*
|
||||
* The *_NF* (Normalization Form) flags are mutually exclusive; at most one
|
||||
* of them may be supplied.
|
||||
*/
|
||||
void
|
||||
mzap_create_impl(objset_t *os, uint64_t obj, int normflags, zap_flags_t flags,
|
||||
dmu_tx_t *tx)
|
||||
@ -789,7 +832,7 @@ mzap_normalization_conflict(zap_t *zap, zap_name_t *zn, mzap_ent_t *mze)
|
||||
|
||||
if (zn == NULL) {
|
||||
zn = zap_name_alloc(zap, MZE_PHYS(zap, mze)->mze_name,
|
||||
MT_FIRST);
|
||||
MT_NORMALIZE);
|
||||
allocdzn = B_TRUE;
|
||||
}
|
||||
if (zap_match(zn, MZE_PHYS(zap, other)->mze_name)) {
|
||||
@ -818,7 +861,7 @@ zap_lookup(objset_t *os, uint64_t zapobj, const char *name,
|
||||
uint64_t integer_size, uint64_t num_integers, void *buf)
|
||||
{
|
||||
return (zap_lookup_norm(os, zapobj, name, integer_size,
|
||||
num_integers, buf, MT_EXACT, NULL, 0, NULL));
|
||||
num_integers, buf, 0, NULL, 0, NULL));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -886,7 +929,7 @@ zap_lookup_by_dnode(dnode_t *dn, const char *name,
|
||||
uint64_t integer_size, uint64_t num_integers, void *buf)
|
||||
{
|
||||
return (zap_lookup_norm_by_dnode(dn, name, integer_size,
|
||||
num_integers, buf, MT_EXACT, NULL, 0, NULL));
|
||||
num_integers, buf, 0, NULL, 0, NULL));
|
||||
}
|
||||
|
||||
int
|
||||
@ -959,7 +1002,7 @@ int
|
||||
zap_contains(objset_t *os, uint64_t zapobj, const char *name)
|
||||
{
|
||||
int err = zap_lookup_norm(os, zapobj, name, 0,
|
||||
0, NULL, MT_EXACT, NULL, 0, NULL);
|
||||
0, NULL, 0, NULL, 0, NULL);
|
||||
if (err == EOVERFLOW || err == EINVAL)
|
||||
err = 0; /* found, but skipped reading the value */
|
||||
return (err);
|
||||
@ -977,7 +1020,7 @@ zap_length(objset_t *os, uint64_t zapobj, const char *name,
|
||||
err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap);
|
||||
if (err)
|
||||
return (err);
|
||||
zn = zap_name_alloc(zap, name, MT_EXACT);
|
||||
zn = zap_name_alloc(zap, name, 0);
|
||||
if (zn == NULL) {
|
||||
zap_unlockdir(zap, FTAG);
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
@ -1080,7 +1123,7 @@ zap_add(objset_t *os, uint64_t zapobj, const char *key,
|
||||
err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, FTAG, &zap);
|
||||
if (err)
|
||||
return (err);
|
||||
zn = zap_name_alloc(zap, key, MT_EXACT);
|
||||
zn = zap_name_alloc(zap, key, 0);
|
||||
if (zn == NULL) {
|
||||
zap_unlockdir(zap, FTAG);
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
@ -1159,7 +1202,7 @@ zap_update(objset_t *os, uint64_t zapobj, const char *name,
|
||||
err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, FTAG, &zap);
|
||||
if (err)
|
||||
return (err);
|
||||
zn = zap_name_alloc(zap, name, MT_EXACT);
|
||||
zn = zap_name_alloc(zap, name, 0);
|
||||
if (zn == NULL) {
|
||||
zap_unlockdir(zap, FTAG);
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
@ -1222,7 +1265,7 @@ zap_update_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
|
||||
int
|
||||
zap_remove(objset_t *os, uint64_t zapobj, const char *name, dmu_tx_t *tx)
|
||||
{
|
||||
return (zap_remove_norm(os, zapobj, name, MT_EXACT, tx));
|
||||
return (zap_remove_norm(os, zapobj, name, 0, tx));
|
||||
}
|
||||
|
||||
int
|
||||
@ -1474,7 +1517,7 @@ zap_count_write_by_dnode(dnode_t *dn, const char *name, int add,
|
||||
return (err);
|
||||
|
||||
if (!zap->zap_ismicro) {
|
||||
zap_name_t *zn = zap_name_alloc(zap, name, MT_EXACT);
|
||||
zap_name_t *zn = zap_name_alloc(zap, name, 0);
|
||||
if (zn) {
|
||||
err = fzap_count_write(zn, add, towrite,
|
||||
tooverwrite);
|
||||
|
@ -18,9 +18,11 @@
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2015 by Delphix. All rights reserved.
|
||||
* Copyright 2017 Nexenta Systems, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -62,13 +64,12 @@
|
||||
* of names after deciding which is the appropriate lookup interface.
|
||||
*/
|
||||
static int
|
||||
zfs_match_find(zfsvfs_t *zfsvfs, znode_t *dzp, char *name, boolean_t exact,
|
||||
zfs_match_find(zfsvfs_t *zfsvfs, znode_t *dzp, char *name, matchtype_t mt,
|
||||
boolean_t update, int *deflags, pathname_t *rpnp, uint64_t *zoid)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (zfsvfs->z_norm) {
|
||||
matchtype_t mt = MT_FIRST;
|
||||
boolean_t conflict = B_FALSE;
|
||||
size_t bufsz = 0;
|
||||
char *buf = NULL;
|
||||
@ -77,8 +78,7 @@ zfs_match_find(zfsvfs_t *zfsvfs, znode_t *dzp, char *name, boolean_t exact,
|
||||
buf = rpnp->pn_buf;
|
||||
bufsz = rpnp->pn_bufsize;
|
||||
}
|
||||
if (exact)
|
||||
mt = MT_EXACT;
|
||||
|
||||
/*
|
||||
* In the non-mixed case we only expect there would ever
|
||||
* be one match, but we need to use the normalizing lookup.
|
||||
@ -140,7 +140,7 @@ zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
|
||||
zfsvfs_t *zfsvfs = dzp->z_zfsvfs;
|
||||
zfs_dirlock_t *dl;
|
||||
boolean_t update;
|
||||
boolean_t exact;
|
||||
matchtype_t mt = 0;
|
||||
uint64_t zoid;
|
||||
vnode_t *vp = NULL;
|
||||
int error = 0;
|
||||
@ -175,13 +175,29 @@ zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
|
||||
*/
|
||||
|
||||
/*
|
||||
* Decide if exact matches should be requested when performing
|
||||
* a zap lookup on file systems supporting case-insensitive
|
||||
* access.
|
||||
* When matching we may need to normalize & change case according to
|
||||
* FS settings.
|
||||
*
|
||||
* Note that a normalized match is necessary for a case insensitive
|
||||
* filesystem when the lookup request is not exact because normalization
|
||||
* can fold case independent of normalizing code point sequences.
|
||||
*
|
||||
* See the table above zfs_dropname().
|
||||
*/
|
||||
exact =
|
||||
((zfsvfs->z_case == ZFS_CASE_INSENSITIVE) && (flag & ZCIEXACT)) ||
|
||||
((zfsvfs->z_case == ZFS_CASE_MIXED) && !(flag & ZCILOOK));
|
||||
if (zfsvfs->z_norm != 0) {
|
||||
mt = MT_NORMALIZE;
|
||||
|
||||
/*
|
||||
* Determine if the match needs to honor the case specified in
|
||||
* lookup, and if so keep track of that so that during
|
||||
* normalization we don't fold case.
|
||||
*/
|
||||
if ((zfsvfs->z_case == ZFS_CASE_INSENSITIVE &&
|
||||
(flag & ZCIEXACT)) ||
|
||||
(zfsvfs->z_case == ZFS_CASE_MIXED && !(flag & ZCILOOK))) {
|
||||
mt |= MT_MATCH_CASE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Only look in or update the DNLC if we are looking for the
|
||||
@ -194,7 +210,7 @@ zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
|
||||
* case for performance improvement?
|
||||
*/
|
||||
update = !zfsvfs->z_norm ||
|
||||
((zfsvfs->z_case == ZFS_CASE_MIXED) &&
|
||||
(zfsvfs->z_case == ZFS_CASE_MIXED &&
|
||||
!(zfsvfs->z_norm & ~U8_TEXTPREP_TOUPPER) && !(flag & ZCILOOK));
|
||||
|
||||
/*
|
||||
@ -308,7 +324,7 @@ zfs_dirent_lock(zfs_dirlock_t **dlpp, znode_t *dzp, char *name, znode_t **zpp,
|
||||
*zpp = VTOZ(vp);
|
||||
return (0);
|
||||
} else {
|
||||
error = zfs_match_find(zfsvfs, dzp, name, exact,
|
||||
error = zfs_match_find(zfsvfs, dzp, name, mt,
|
||||
update, direntflags, realpnp, &zoid);
|
||||
}
|
||||
}
|
||||
@ -774,6 +790,28 @@ zfs_link_create(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The match type in the code for this function should conform to:
|
||||
*
|
||||
* ------------------------------------------------------------------------
|
||||
* fs type | z_norm | lookup type | match type
|
||||
* ---------|-------------|-------------|----------------------------------
|
||||
* CS !norm | 0 | 0 | 0 (exact)
|
||||
* CS norm | formX | 0 | MT_NORMALIZE
|
||||
* CI !norm | upper | !ZCIEXACT | MT_NORMALIZE
|
||||
* CI !norm | upper | ZCIEXACT | MT_NORMALIZE | MT_MATCH_CASE
|
||||
* CI norm | upper|formX | !ZCIEXACT | MT_NORMALIZE
|
||||
* CI norm | upper|formX | ZCIEXACT | MT_NORMALIZE | MT_MATCH_CASE
|
||||
* CM !norm | upper | !ZCILOOK | MT_NORMALIZE | MT_MATCH_CASE
|
||||
* CM !norm | upper | ZCILOOK | MT_NORMALIZE
|
||||
* CM norm | upper|formX | !ZCILOOK | MT_NORMALIZE | MT_MATCH_CASE
|
||||
* CM norm | upper|formX | ZCILOOK | MT_NORMALIZE
|
||||
*
|
||||
* Abbreviations:
|
||||
* CS = Case Sensitive, CI = Case Insensitive, CM = Case Mixed
|
||||
* upper = case folding set by fs type on creation (U8_TEXTPREP_TOUPPER)
|
||||
* formX = unicode normalization form set on fs creation
|
||||
*/
|
||||
static int
|
||||
zfs_dropname(zfs_dirlock_t *dl, znode_t *zp, znode_t *dzp, dmu_tx_t *tx,
|
||||
int flag)
|
||||
@ -781,18 +819,20 @@ zfs_dropname(zfs_dirlock_t *dl, znode_t *zp, znode_t *dzp, dmu_tx_t *tx,
|
||||
int error;
|
||||
|
||||
if (zp->z_zfsvfs->z_norm) {
|
||||
if (((zp->z_zfsvfs->z_case == ZFS_CASE_INSENSITIVE) &&
|
||||
matchtype_t mt = MT_NORMALIZE;
|
||||
|
||||
if ((zp->z_zfsvfs->z_case == ZFS_CASE_INSENSITIVE &&
|
||||
(flag & ZCIEXACT)) ||
|
||||
((zp->z_zfsvfs->z_case == ZFS_CASE_MIXED) &&
|
||||
!(flag & ZCILOOK)))
|
||||
error = zap_remove_norm(zp->z_zfsvfs->z_os,
|
||||
dzp->z_id, dl->dl_name, MT_EXACT, tx);
|
||||
else
|
||||
error = zap_remove_norm(zp->z_zfsvfs->z_os,
|
||||
dzp->z_id, dl->dl_name, MT_FIRST, tx);
|
||||
(zp->z_zfsvfs->z_case == ZFS_CASE_MIXED &&
|
||||
!(flag & ZCILOOK))) {
|
||||
mt |= MT_MATCH_CASE;
|
||||
}
|
||||
|
||||
error = zap_remove_norm(zp->z_zfsvfs->z_os, dzp->z_id,
|
||||
dl->dl_name, mt, tx);
|
||||
} else {
|
||||
error = zap_remove(zp->z_zfsvfs->z_os,
|
||||
dzp->z_id, dl->dl_name, tx);
|
||||
error = zap_remove(zp->z_zfsvfs->z_os, dzp->z_id, dl->dl_name,
|
||||
tx);
|
||||
}
|
||||
|
||||
return (error);
|
||||
|
@ -18,12 +18,13 @@
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
|
||||
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2014 Integros [integros.com]
|
||||
* Copyright 2015 Joyent, Inc.
|
||||
* Copyright 2017 Nexenta Systems, Inc.
|
||||
*/
|
||||
|
||||
/* Portions Copyright 2007 Jeremy Teo */
|
||||
@ -1237,7 +1238,15 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
|
||||
zfsvfs_t *zfsvfs = zdp->z_zfsvfs;
|
||||
int error = 0;
|
||||
|
||||
/* fast path */
|
||||
/*
|
||||
* Fast path lookup, however we must skip DNLC lookup
|
||||
* for case folding or normalizing lookups because the
|
||||
* DNLC code only stores the passed in name. This means
|
||||
* creating 'a' and removing 'A' on a case insensitive
|
||||
* file system would work, but DNLC still thinks 'a'
|
||||
* exists and won't let you create it again on the next
|
||||
* pass through fast path.
|
||||
*/
|
||||
if (!(flags & (LOOKUP_XATTR | FIGNORECASE))) {
|
||||
|
||||
if (dvp->v_type != VDIR) {
|
||||
@ -1254,7 +1263,9 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
|
||||
return (0);
|
||||
}
|
||||
return (error);
|
||||
} else {
|
||||
} else if (!zdp->z_zfsvfs->z_norm &&
|
||||
(zdp->z_zfsvfs->z_case == ZFS_CASE_SENSITIVE)) {
|
||||
|
||||
vnode_t *tvp = dnlc_lookup(dvp, nm);
|
||||
|
||||
if (tvp) {
|
||||
|
Loading…
Reference in New Issue
Block a user