aboutsummaryrefslogtreecommitdiff
path: root/ubifs-utils/mkfs.ubifs/key.h
blob: 39379fd4817840e0f546fc530b7153cfc312e088 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*
 * This file is part of UBIFS.
 *
 * Copyright (C) 2006-2008 Nokia Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 *
 * Authors: Artem Bityutskiy (Битюцкий Артём)
 *          Adrian Hunter
 */

/*
 * This header contains various key-related definitions and helper function.
 * UBIFS allows several key schemes, so we access key fields only via these
 * helpers. At the moment only one key scheme is supported.
 *
 * Simple key scheme
 * ~~~~~~~~~~~~~~~~~
 *
 * Keys are 64-bits long. First 32-bits are inode number (parent inode number
 * in case of direntry key). Next 3 bits are node type. The last 29 bits are
 * 4KiB offset in case of inode node, and direntry hash in case of a direntry
 * node. We use "r5" hash borrowed from reiserfs.
 */

#ifndef __UBIFS_KEY_H__
#define __UBIFS_KEY_H__

/**
 * key_mask_hash - mask a valid hash value.
 * @val: value to be masked
 *
 * We use hash values as offset in directories, so values %0 and %1 are
 * reserved for "." and "..". %2 is reserved for "end of readdir" marker. This
 * function makes sure the reserved values are not used.
 */
static inline uint32_t key_mask_hash(uint32_t hash)
{
	hash &= UBIFS_S_KEY_HASH_MASK;
	if (unlikely(hash <= 2))
		hash += 3;
	return hash;
}

/**
 * key_r5_hash - R5 hash function (borrowed from reiserfs).
 * @s: direntry name
 * @len: name length
 */
static inline uint32_t key_r5_hash(const char *s, int len)
{
	uint32_t a = 0;
	const signed char *str = (const signed char *)s;

	len = len;
	while (*str) {
		a += *str << 4;
		a += *str >> 4;
		a *= 11;
		str++;
	}

	return key_mask_hash(a);
}

/**
 * key_test_hash - testing hash function.
 * @str: direntry name
 * @len: name length
 */
static inline uint32_t key_test_hash(const char *str, int len)
{
	uint32_t a = 0;

	len = min_t(uint32_t, len, 4);
	memcpy(&a, str, len);
	return key_mask_hash(a);
}

/**
 * ino_key_init - initialize inode key.
 * @c: UBIFS file-system description object
 * @key: key to initialize
 * @inum: inode number
 */
static inline void ino_key_init(union ubifs_key *key, ino_t inum)
{
	key->u32[0] = inum;
	key->u32[1] = UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS;
}

/**
 * dent_key_init - initialize directory entry key.
 * @c: UBIFS file-system description object
 * @key: key to initialize
 * @inum: parent inode number
 * @nm: direntry name and length
 */
static inline void dent_key_init(const struct ubifs_info *c,
				 union ubifs_key *key, ino_t inum,
				 const struct qstr *nm)
{
	uint32_t hash = c->key_hash(nm->name, nm->len);

	ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
	key->u32[0] = inum;
	key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS);
}

/**
 * xent_key_init - initialize extended attribute entry key.
 * @c: UBIFS file-system description object
 * @key: key to initialize
 * @inum: host inode number
 * @nm: extended attribute entry name and length
 */
static inline void xent_key_init(const struct ubifs_info *c,
				 union ubifs_key *key, ino_t inum,
				 const struct qstr *nm)
{
	uint32_t hash = c->key_hash(nm->name, nm->len);

	ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
	key->u32[0] = inum;
	key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS);
}

/**
 * data_key_init - initialize data key.
 * @c: UBIFS file-system description object
 * @key: key to initialize
 * @inum: inode number
 * @block: block number
 */
static inline void data_key_init(union ubifs_key *key, ino_t inum,
				 unsigned int block)
{
	ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK));
	key->u32[0] = inum;
	key->u32[1] = block | (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS);
}

/**
 * key_write - transform a key from in-memory format.
 * @c: UBIFS file-system description object
 * @from: the key to transform
 * @to: the key to store the result
 */
static inline void key_write(const union ubifs_key *from, void *to)
{
	union ubifs_key *t = to;

	t->j32[0] = cpu_to_le32(from->u32[0]);
	t->j32[1] = cpu_to_le32(from->u32[1]);
	memset(to + 8, 0, UBIFS_MAX_KEY_LEN - 8);
}

/**
 * key_write_idx - transform a key from in-memory format for the index.
 * @c: UBIFS file-system description object
 * @from: the key to transform
 * @to: the key to store the result
 */
static inline void key_write_idx(const union ubifs_key *from, void *to)
{
	union ubifs_key *t = to;

	t->j32[0] = cpu_to_le32(from->u32[0]);
	t->j32[1] = cpu_to_le32(from->u32[1]);
}

/**
 * keys_cmp - compare keys.
 * @c: UBIFS file-system description object
 * @key1: the first key to compare
 * @key2: the second key to compare
 *
 * This function compares 2 keys and returns %-1 if @key1 is less than
 * @key2, 0 if the keys are equivalent and %1 if @key1 is greater than @key2.
 */
static inline int keys_cmp(const union ubifs_key *key1,
			   const union ubifs_key *key2)
{
	if (key1->u32[0] < key2->u32[0])
		return -1;
	if (key1->u32[0] > key2->u32[0])
		return 1;
	if (key1->u32[1] < key2->u32[1])
		return -1;
	if (key1->u32[1] > key2->u32[1])
		return 1;

	return 0;
}

#endif /* !__UBIFS_KEY_H__ */