dir-item.c 6.8 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
#include <linux/module.h>
20 21 22
#include "ctree.h"
#include "disk-io.h"
#include "hash.h"
23
#include "transaction.h"
24

C
Chris Mason 已提交
25 26 27 28 29
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 已提交
30 31 32
						   u32 data_size,
						   const char *name,
						   int name_len)
33 34
{
	int ret;
35 36 37
	char *ptr;
	struct btrfs_item *item;
	struct btrfs_leaf *leaf;
38 39

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

59
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
60 61
			  *root, const char *name, int name_len, u64 dir,
			  struct btrfs_key *location, u8 type)
62 63
{
	int ret = 0;
C
Chris Mason 已提交
64
	int ret2 = 0;
65
	struct btrfs_path *path;
66 67 68 69 70 71 72
	struct btrfs_dir_item *dir_item;
	char *name_ptr;
	struct btrfs_key key;
	u32 data_size;

	key.objectid = dir;
	key.flags = 0;
73
	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
C
Chris Mason 已提交
74
	ret = btrfs_name_hash(name, name_len, &key.offset);
75
	BUG_ON(ret);
76
	path = btrfs_alloc_path();
77
	data_size = sizeof(*dir_item) + name_len;
C
Chris Mason 已提交
78 79
	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
					name, name_len);
80 81
	if (IS_ERR(dir_item)) {
		ret = PTR_ERR(dir_item);
C
Chris Mason 已提交
82 83
		if (ret == -EEXIST)
			goto second_insert;
84
		goto out;
85
	}
86

87
	btrfs_cpu_key_to_disk(&dir_item->location, location);
88 89
	btrfs_set_dir_type(dir_item, type);
	btrfs_set_dir_flags(dir_item, 0);
90
	btrfs_set_dir_name_len(dir_item, name_len);
91
	name_ptr = (char *)(dir_item + 1);
C
Chris Mason 已提交
92 93 94

	btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
	btrfs_mark_buffer_dirty(path->nodes[0]);
95

C
Chris Mason 已提交
96
second_insert:
97 98 99 100 101
	/* FIXME, use some real flag for selecting the extra index */
	if (root == root->fs_info->tree_root) {
		ret = 0;
		goto out;
	}
102
	btrfs_release_path(root, path);
103 104 105

	btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
	key.offset = location->objectid;
C
Chris Mason 已提交
106 107
	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
					name, name_len);
108
	if (IS_ERR(dir_item)) {
C
Chris Mason 已提交
109
		ret2 = PTR_ERR(dir_item);
110 111 112 113 114 115 116 117 118 119
		goto out;
	}
	btrfs_cpu_key_to_disk(&dir_item->location, location);
	btrfs_set_dir_type(dir_item, type);
	btrfs_set_dir_flags(dir_item, 0);
	btrfs_set_dir_name_len(dir_item, name_len);
	name_ptr = (char *)(dir_item + 1);
	btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
	btrfs_mark_buffer_dirty(path->nodes[0]);
out:
120
	btrfs_free_path(path);
C
Chris Mason 已提交
121 122 123 124 125
	if (ret)
		return ret;
	if (ret2)
		return ret2;
	return 0;
126 127
}

128 129 130 131 132
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)
133
{
134
	int ret;
135
	struct btrfs_key key;
136 137
	int ins_len = mod < 0 ? -1 : 0;
	int cow = mod != 0;
138 139
	struct btrfs_disk_key *found_key;
	struct btrfs_leaf *leaf;
140 141 142

	key.objectid = dir;
	key.flags = 0;
143
	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
144 145
	ret = btrfs_name_hash(name, name_len, &key.offset);
	BUG_ON(ret);
146 147 148 149 150 151 152
	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]--;
153
	}
154 155 156 157 158 159 160 161 162
	leaf = btrfs_buffer_leaf(path->nodes[0]);
	found_key = &leaf->items[path->slots[0]].key;

	if (btrfs_disk_key_objectid(found_key) != dir ||
	    btrfs_disk_key_type(found_key) != BTRFS_DIR_ITEM_KEY ||
	    btrfs_disk_key_offset(found_key) != key.offset)
		return NULL;

	return btrfs_match_dir_item_name(root, path, name, name_len);
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
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;
	key.flags = 0;
	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);
}

struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
191 192
			      struct btrfs_path *path,
			      const char *name, int name_len)
193 194 195
{
	struct btrfs_dir_item *dir_item;
	char *name_ptr;
196 197 198 199
	u32 total_len;
	u32 cur = 0;
	u32 this_len;
	struct btrfs_leaf *leaf;
200

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
	leaf = btrfs_buffer_leaf(path->nodes[0]);
	dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
	total_len = btrfs_item_size(leaf->items + path->slots[0]);
	while(cur < total_len) {
		this_len = sizeof(*dir_item) + btrfs_dir_name_len(dir_item);
		name_ptr = (char *)(dir_item + 1);

		if (btrfs_dir_name_len(dir_item) == name_len &&
		    memcmp(name_ptr, name, name_len) == 0)
			return dir_item;

		cur += this_len;
		dir_item = (struct btrfs_dir_item *)((char *)dir_item +
						     this_len);
	}
	return NULL;
217
}
218 219 220 221 222 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

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

	struct btrfs_leaf *leaf;
	u32 sub_item_len;
	u32 item_len;
	int ret;

	leaf = btrfs_buffer_leaf(path->nodes[0]);
	sub_item_len = sizeof(*di) + btrfs_dir_name_len(di);
	item_len = btrfs_item_size(leaf->items + path->slots[0]);
	if (sub_item_len == btrfs_item_size(leaf->items + path->slots[0])) {
		ret = btrfs_del_item(trans, root, path);
		BUG_ON(ret);
	} else {
		char *ptr = (char *)di;
		char *start = btrfs_item_ptr(leaf, path->slots[0], char);
		btrfs_memmove(root, leaf, ptr, ptr + sub_item_len,
			item_len - (ptr + sub_item_len - start));
		ret = btrfs_truncate_item(trans, root, path,
					  item_len - sub_item_len);
		BUG_ON(ret);
	}
	return 0;
}