dir-item.c 9.7 KB
Newer Older
C
Chris Mason 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Copyright (C) 2007 Oracle.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License v2 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., 59 Temple Place - Suite 330,
 * Boston, MA 021110-1307, USA.
 */

19 20 21
#include "ctree.h"
#include "disk-io.h"
#include "hash.h"
22
#include "transaction.h"
23

C
Chris Mason 已提交
24 25 26 27 28
static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
						   *trans,
						   struct btrfs_root *root,
						   struct btrfs_path *path,
						   struct btrfs_key *cpu_key,
C
Chris Mason 已提交
29 30 31
						   u32 data_size,
						   const char *name,
						   int name_len)
32 33
{
	int ret;
34 35
	char *ptr;
	struct btrfs_item *item;
36
	struct extent_buffer *leaf;
37 38

	ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
39
	if (ret == -EEXIST) {
C
Chris Mason 已提交
40 41 42 43
		struct btrfs_dir_item *di;
		di = btrfs_match_dir_item_name(root, path, name, name_len);
		if (di)
			return ERR_PTR(-EEXIST);
44 45
		ret = btrfs_extend_item(trans, root, path, data_size);
		WARN_ON(ret > 0);
46
	}
47 48
	if (ret < 0)
		return ERR_PTR(ret);
49
	WARN_ON(ret > 0);
50 51
	leaf = path->nodes[0];
	item = btrfs_item_nr(leaf, path->slots[0]);
52
	ptr = btrfs_item_ptr(leaf, path->slots[0], char);
53 54
	BUG_ON(data_size > btrfs_item_size(leaf, item));
	ptr += btrfs_item_size(leaf, item) - data_size;
55
	return (struct btrfs_dir_item *)ptr;
56 57
}

J
Josef Bacik 已提交
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
			    struct btrfs_root *root, const char *name,
			    u16 name_len, const void *data, u16 data_len,
			    u64 dir)
{
	int ret = 0;
	struct btrfs_path *path;
	struct btrfs_dir_item *dir_item;
	unsigned long name_ptr, data_ptr;
	struct btrfs_key key, location;
	struct btrfs_disk_key disk_key;
	struct extent_buffer *leaf;
	u32 data_size;

	key.objectid = dir;
	btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
	ret = btrfs_name_hash(name, name_len, &key.offset);
	BUG_ON(ret);
	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;
Y
Yan 已提交
79 80 81
	if (name_len + data_len + sizeof(struct btrfs_dir_item) >
	    BTRFS_LEAF_DATA_SIZE(root) - sizeof(struct btrfs_item))
		return -ENOSPC;
J
Josef Bacik 已提交
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

	data_size = sizeof(*dir_item) + name_len + data_len;
	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
					name, name_len);
	/*
	 * FIXME: at some point we should handle xattr's that are larger than
	 * what we can fit in our leaf.  We set location to NULL b/c we arent
	 * pointing at anything else, that will change if we store the xattr
	 * data in a separate inode.
	 */
	BUG_ON(IS_ERR(dir_item));
	memset(&location, 0, sizeof(location));

	leaf = path->nodes[0];
	btrfs_cpu_key_to_disk(&disk_key, &location);
	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
	btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR);
	btrfs_set_dir_name_len(leaf, dir_item, name_len);
	btrfs_set_dir_data_len(leaf, dir_item, data_len);
	name_ptr = (unsigned long)(dir_item + 1);
	data_ptr = (unsigned long)((char *)name_ptr + name_len);

	write_extent_buffer(leaf, name, name_ptr, name_len);
	write_extent_buffer(leaf, data, data_ptr, data_len);
	btrfs_mark_buffer_dirty(path->nodes[0]);

	btrfs_free_path(path);
	return ret;
}

112
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
113 114
			  *root, const char *name, int name_len, u64 dir,
			  struct btrfs_key *location, u8 type)
115 116
{
	int ret = 0;
C
Chris Mason 已提交
117
	int ret2 = 0;
118
	struct btrfs_path *path;
119
	struct btrfs_dir_item *dir_item;
120 121
	struct extent_buffer *leaf;
	unsigned long name_ptr;
122
	struct btrfs_key key;
123
	struct btrfs_disk_key disk_key;
124 125 126
	u32 data_size;

	key.objectid = dir;
127
	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
C
Chris Mason 已提交
128
	ret = btrfs_name_hash(name, name_len, &key.offset);
129
	BUG_ON(ret);
130
	path = btrfs_alloc_path();
131
	data_size = sizeof(*dir_item) + name_len;
C
Chris Mason 已提交
132 133
	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
					name, name_len);
134 135
	if (IS_ERR(dir_item)) {
		ret = PTR_ERR(dir_item);
C
Chris Mason 已提交
136 137
		if (ret == -EEXIST)
			goto second_insert;
138
		goto out;
139
	}
140

141 142 143 144
	leaf = path->nodes[0];
	btrfs_cpu_key_to_disk(&disk_key, location);
	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
	btrfs_set_dir_type(leaf, dir_item, type);
J
Josef Bacik 已提交
145
	btrfs_set_dir_data_len(leaf, dir_item, 0);
146 147
	btrfs_set_dir_name_len(leaf, dir_item, name_len);
	name_ptr = (unsigned long)(dir_item + 1);
C
Chris Mason 已提交
148

149 150
	write_extent_buffer(leaf, name, name_ptr, name_len);
	btrfs_mark_buffer_dirty(leaf);
151

C
Chris Mason 已提交
152
second_insert:
153 154 155 156 157
	/* FIXME, use some real flag for selecting the extra index */
	if (root == root->fs_info->tree_root) {
		ret = 0;
		goto out;
	}
158
	btrfs_release_path(root, path);
159 160 161

	btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
	key.offset = location->objectid;
C
Chris Mason 已提交
162 163
	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
					name, name_len);
164
	if (IS_ERR(dir_item)) {
C
Chris Mason 已提交
165
		ret2 = PTR_ERR(dir_item);
166 167
		goto out;
	}
168 169 170 171
	leaf = path->nodes[0];
	btrfs_cpu_key_to_disk(&disk_key, location);
	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
	btrfs_set_dir_type(leaf, dir_item, type);
J
Josef Bacik 已提交
172
	btrfs_set_dir_data_len(leaf, dir_item, 0);
173 174 175 176
	btrfs_set_dir_name_len(leaf, dir_item, name_len);
	name_ptr = (unsigned long)(dir_item + 1);
	write_extent_buffer(leaf, name, name_ptr, name_len);
	btrfs_mark_buffer_dirty(leaf);
177
out:
178
	btrfs_free_path(path);
C
Chris Mason 已提交
179 180 181 182 183
	if (ret)
		return ret;
	if (ret2)
		return ret2;
	return 0;
184 185
}

186 187 188 189 190
struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
					     struct btrfs_root *root,
					     struct btrfs_path *path, u64 dir,
					     const char *name, int name_len,
					     int mod)
191
{
192
	int ret;
193
	struct btrfs_key key;
194 195
	int ins_len = mod < 0 ? -1 : 0;
	int cow = mod != 0;
196 197
	struct btrfs_key found_key;
	struct extent_buffer *leaf;
198 199

	key.objectid = dir;
200
	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
201

202 203
	ret = btrfs_name_hash(name, name_len, &key.offset);
	BUG_ON(ret);
204

205 206 207 208 209 210 211
	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
	if (ret < 0)
		return ERR_PTR(ret);
	if (ret > 0) {
		if (path->slots[0] == 0)
			return NULL;
		path->slots[0]--;
212
	}
213

214 215 216 217 218 219
	leaf = path->nodes[0];
	btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);

	if (found_key.objectid != dir ||
	    btrfs_key_type(&found_key) != BTRFS_DIR_ITEM_KEY ||
	    found_key.offset != key.offset)
220 221 222
		return NULL;

	return btrfs_match_dir_item_name(root, path, name, name_len);
223 224
}

225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
struct btrfs_dir_item *
btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
			    struct btrfs_root *root,
			    struct btrfs_path *path, u64 dir,
			    u64 objectid, const char *name, int name_len,
			    int mod)
{
	int ret;
	struct btrfs_key key;
	int ins_len = mod < 0 ? -1 : 0;
	int cow = mod != 0;

	key.objectid = dir;
	btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
	key.offset = objectid;

	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
	if (ret < 0)
		return ERR_PTR(ret);
	if (ret > 0)
		return ERR_PTR(-ENOENT);
	return btrfs_match_dir_item_name(root, path, name, name_len);
}

J
Josef Bacik 已提交
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
					  struct btrfs_root *root,
					  struct btrfs_path *path, u64 dir,
					  const char *name, u16 name_len,
					  int mod)
{
	int ret;
	struct btrfs_key key;
	int ins_len = mod < 0 ? -1 : 0;
	int cow = mod != 0;
	struct btrfs_key found_key;
	struct extent_buffer *leaf;

	key.objectid = dir;
	btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
	ret = btrfs_name_hash(name, name_len, &key.offset);
	BUG_ON(ret);
	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
	if (ret < 0)
		return ERR_PTR(ret);
	if (ret > 0) {
		if (path->slots[0] == 0)
			return NULL;
		path->slots[0]--;
	}

	leaf = path->nodes[0];
	btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);

	if (found_key.objectid != dir ||
	    btrfs_key_type(&found_key) != BTRFS_XATTR_ITEM_KEY ||
	    found_key.offset != key.offset)
		return NULL;

	return btrfs_match_dir_item_name(root, path, name, name_len);
}

286
struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
287 288
			      struct btrfs_path *path,
			      const char *name, int name_len)
289 290
{
	struct btrfs_dir_item *dir_item;
291
	unsigned long name_ptr;
292 293 294
	u32 total_len;
	u32 cur = 0;
	u32 this_len;
295
	struct extent_buffer *leaf;
296

297
	leaf = path->nodes[0];
298
	dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
299
	total_len = btrfs_item_size_nr(leaf, path->slots[0]);
300
	while(cur < total_len) {
301
		this_len = sizeof(*dir_item) +
J
Josef Bacik 已提交
302 303
			btrfs_dir_name_len(leaf, dir_item) +
			btrfs_dir_data_len(leaf, dir_item);
304
		name_ptr = (unsigned long)(dir_item + 1);
305

306 307
		if (btrfs_dir_name_len(leaf, dir_item) == name_len &&
		    memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)
308 309 310 311 312 313 314
			return dir_item;

		cur += this_len;
		dir_item = (struct btrfs_dir_item *)((char *)dir_item +
						     this_len);
	}
	return NULL;
315
}
316 317 318 319 320 321 322

int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
			      struct btrfs_root *root,
			      struct btrfs_path *path,
			      struct btrfs_dir_item *di)
{

323
	struct extent_buffer *leaf;
324 325
	u32 sub_item_len;
	u32 item_len;
326
	int ret = 0;
327

328
	leaf = path->nodes[0];
J
Josef Bacik 已提交
329 330
	sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) +
		btrfs_dir_data_len(leaf, di);
331 332
	item_len = btrfs_item_size_nr(leaf, path->slots[0]);
	if (sub_item_len == item_len) {
333 334
		ret = btrfs_del_item(trans, root, path);
	} else {
335 336 337 338 339 340
		/* MARKER */
		unsigned long ptr = (unsigned long)di;
		unsigned long start;

		start = btrfs_item_ptr_offset(leaf, path->slots[0]);
		memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
341 342
			item_len - (ptr + sub_item_len - start));
		ret = btrfs_truncate_item(trans, root, path,
343
					  item_len - sub_item_len, 1);
344 345 346 347
	}
	return 0;
}