blob: 00a28d90fea66372b851933ff18130acd1cd6806 [file] [log] [blame]
Chris Mason2e635a22007-03-21 11:12:56 -04001#include <linux/module.h>
Chris Mason62e27492007-03-15 12:56:47 -04002#include "ctree.h"
3#include "disk-io.h"
4#include "hash.h"
Chris Masone089f052007-03-16 16:20:31 -04005#include "transaction.h"
Chris Mason62e27492007-03-15 12:56:47 -04006
Chris Mason35b7e472007-05-02 15:53:43 -04007static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
8 *trans,
9 struct btrfs_root *root,
10 struct btrfs_path *path,
11 struct btrfs_key *cpu_key,
12 u32 data_size)
Chris Mason7fcde0e2007-04-05 12:13:21 -040013{
Chris Mason7fcde0e2007-04-05 12:13:21 -040014 int ret;
Chris Mason7e381802007-04-19 15:36:27 -040015 char *ptr;
16 struct btrfs_item *item;
17 struct btrfs_leaf *leaf;
Chris Mason7fcde0e2007-04-05 12:13:21 -040018
19 ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
Chris Mason7e381802007-04-19 15:36:27 -040020 if (ret == -EEXIST) {
21 ret = btrfs_extend_item(trans, root, path, data_size);
22 WARN_ON(ret > 0);
23 if (ret)
24 return ERR_PTR(ret);
Chris Mason7fcde0e2007-04-05 12:13:21 -040025 }
Chris Mason7e381802007-04-19 15:36:27 -040026 WARN_ON(ret > 0);
27 leaf = btrfs_buffer_leaf(path->nodes[0]);
28 item = leaf->items + path->slots[0];
29 ptr = btrfs_item_ptr(leaf, path->slots[0], char);
30 BUG_ON(data_size > btrfs_item_size(item));
31 ptr += btrfs_item_size(item) - data_size;
32 return (struct btrfs_dir_item *)ptr;
Chris Mason7fcde0e2007-04-05 12:13:21 -040033}
34
Chris Masone089f052007-03-16 16:20:31 -040035int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
Chris Masond6e4a422007-04-06 15:37:36 -040036 *root, const char *name, int name_len, u64 dir,
37 struct btrfs_key *location, u8 type)
Chris Mason62e27492007-03-15 12:56:47 -040038{
39 int ret = 0;
Chris Mason5caf2a02007-04-02 11:20:42 -040040 struct btrfs_path *path;
Chris Mason62e27492007-03-15 12:56:47 -040041 struct btrfs_dir_item *dir_item;
42 char *name_ptr;
43 struct btrfs_key key;
44 u32 data_size;
45
46 key.objectid = dir;
47 key.flags = 0;
Chris Mason1d4f6402007-03-15 15:18:43 -040048 btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
Chris Masone20d96d2007-03-22 12:13:20 -040049 ret = btrfs_name_hash(name, name_len, &key.offset);
Chris Mason62e27492007-03-15 12:56:47 -040050 BUG_ON(ret);
Chris Mason5caf2a02007-04-02 11:20:42 -040051 path = btrfs_alloc_path();
52 btrfs_init_path(path);
Chris Mason62e27492007-03-15 12:56:47 -040053 data_size = sizeof(*dir_item) + name_len;
Chris Mason7e381802007-04-19 15:36:27 -040054 dir_item = insert_with_overflow(trans, root, path, &key, data_size);
55 if (IS_ERR(dir_item)) {
56 ret = PTR_ERR(dir_item);
Chris Mason62e27492007-03-15 12:56:47 -040057 goto out;
Chris Mason7e381802007-04-19 15:36:27 -040058 }
Chris Mason62e27492007-03-15 12:56:47 -040059
Chris Masond6e4a422007-04-06 15:37:36 -040060 btrfs_cpu_key_to_disk(&dir_item->location, location);
Chris Mason62e27492007-03-15 12:56:47 -040061 btrfs_set_dir_type(dir_item, type);
62 btrfs_set_dir_flags(dir_item, 0);
Chris Masona8a2ee02007-03-16 08:46:49 -040063 btrfs_set_dir_name_len(dir_item, name_len);
Chris Mason62e27492007-03-15 12:56:47 -040064 name_ptr = (char *)(dir_item + 1);
Chris Masonc5739bb2007-04-10 09:27:04 -040065
66 btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
67 btrfs_mark_buffer_dirty(path->nodes[0]);
Chris Mason7e381802007-04-19 15:36:27 -040068
69 /* FIXME, use some real flag for selecting the extra index */
70 if (root == root->fs_info->tree_root) {
71 ret = 0;
72 goto out;
73 }
74
Chris Mason5caf2a02007-04-02 11:20:42 -040075 btrfs_release_path(root, path);
Chris Mason7e381802007-04-19 15:36:27 -040076
77 btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
78 key.offset = location->objectid;
79 dir_item = insert_with_overflow(trans, root, path, &key, data_size);
80 if (IS_ERR(dir_item)) {
81 ret = PTR_ERR(dir_item);
82 goto out;
83 }
84 btrfs_cpu_key_to_disk(&dir_item->location, location);
85 btrfs_set_dir_type(dir_item, type);
86 btrfs_set_dir_flags(dir_item, 0);
87 btrfs_set_dir_name_len(dir_item, name_len);
88 name_ptr = (char *)(dir_item + 1);
89 btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
90 btrfs_mark_buffer_dirty(path->nodes[0]);
91out:
Chris Mason5caf2a02007-04-02 11:20:42 -040092 btrfs_free_path(path);
Chris Mason62e27492007-03-15 12:56:47 -040093 return ret;
94}
95
Chris Mason7e381802007-04-19 15:36:27 -040096struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
97 struct btrfs_root *root,
98 struct btrfs_path *path, u64 dir,
99 const char *name, int name_len,
100 int mod)
Chris Mason62e27492007-03-15 12:56:47 -0400101{
Chris Mason1d4f6402007-03-15 15:18:43 -0400102 int ret;
Chris Mason62e27492007-03-15 12:56:47 -0400103 struct btrfs_key key;
Chris Mason1d4f6402007-03-15 15:18:43 -0400104 int ins_len = mod < 0 ? -1 : 0;
105 int cow = mod != 0;
Chris Mason7fcde0e2007-04-05 12:13:21 -0400106 struct btrfs_disk_key *found_key;
107 struct btrfs_leaf *leaf;
Chris Mason62e27492007-03-15 12:56:47 -0400108
109 key.objectid = dir;
110 key.flags = 0;
Chris Mason1d4f6402007-03-15 15:18:43 -0400111 btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
Chris Mason62e27492007-03-15 12:56:47 -0400112 ret = btrfs_name_hash(name, name_len, &key.offset);
113 BUG_ON(ret);
Chris Mason7e381802007-04-19 15:36:27 -0400114 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
115 if (ret < 0)
116 return ERR_PTR(ret);
117 if (ret > 0) {
118 if (path->slots[0] == 0)
119 return NULL;
120 path->slots[0]--;
Chris Mason7fcde0e2007-04-05 12:13:21 -0400121 }
Chris Mason7e381802007-04-19 15:36:27 -0400122 leaf = btrfs_buffer_leaf(path->nodes[0]);
123 found_key = &leaf->items[path->slots[0]].key;
124
125 if (btrfs_disk_key_objectid(found_key) != dir ||
126 btrfs_disk_key_type(found_key) != BTRFS_DIR_ITEM_KEY ||
127 btrfs_disk_key_offset(found_key) != key.offset)
128 return NULL;
129
130 return btrfs_match_dir_item_name(root, path, name, name_len);
Chris Mason62e27492007-03-15 12:56:47 -0400131}
132
Chris Mason7e381802007-04-19 15:36:27 -0400133struct btrfs_dir_item *
134btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
135 struct btrfs_root *root,
136 struct btrfs_path *path, u64 dir,
137 u64 objectid, const char *name, int name_len,
138 int mod)
139{
140 int ret;
141 struct btrfs_key key;
142 int ins_len = mod < 0 ? -1 : 0;
143 int cow = mod != 0;
144
145 key.objectid = dir;
146 key.flags = 0;
147 btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
148 key.offset = objectid;
149
150 ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
151 if (ret < 0)
152 return ERR_PTR(ret);
153 if (ret > 0)
154 return ERR_PTR(-ENOENT);
155 return btrfs_match_dir_item_name(root, path, name, name_len);
156}
157
158struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
Chris Mason7f5c1512007-03-23 15:56:19 -0400159 struct btrfs_path *path,
160 const char *name, int name_len)
Chris Mason62e27492007-03-15 12:56:47 -0400161{
Chris Mason62e27492007-03-15 12:56:47 -0400162 struct btrfs_dir_item *dir_item;
163 char *name_ptr;
Chris Mason7e381802007-04-19 15:36:27 -0400164 u32 total_len;
165 u32 cur = 0;
166 u32 this_len;
167 struct btrfs_leaf *leaf;
Chris Masona8a2ee02007-03-16 08:46:49 -0400168
Chris Mason7e381802007-04-19 15:36:27 -0400169 leaf = btrfs_buffer_leaf(path->nodes[0]);
170 dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
171 total_len = btrfs_item_size(leaf->items + path->slots[0]);
172 while(cur < total_len) {
173 this_len = sizeof(*dir_item) + btrfs_dir_name_len(dir_item);
174 name_ptr = (char *)(dir_item + 1);
175
176 if (btrfs_dir_name_len(dir_item) == name_len &&
177 memcmp(name_ptr, name, name_len) == 0)
178 return dir_item;
179
180 cur += this_len;
181 dir_item = (struct btrfs_dir_item *)((char *)dir_item +
182 this_len);
183 }
184 return NULL;
Chris Mason62e27492007-03-15 12:56:47 -0400185}
Chris Mason7e381802007-04-19 15:36:27 -0400186
187int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
188 struct btrfs_root *root,
189 struct btrfs_path *path,
190 struct btrfs_dir_item *di)
191{
192
193 struct btrfs_leaf *leaf;
194 u32 sub_item_len;
195 u32 item_len;
196 int ret;
197
198 leaf = btrfs_buffer_leaf(path->nodes[0]);
199 sub_item_len = sizeof(*di) + btrfs_dir_name_len(di);
200 item_len = btrfs_item_size(leaf->items + path->slots[0]);
201 if (sub_item_len == btrfs_item_size(leaf->items + path->slots[0])) {
202 ret = btrfs_del_item(trans, root, path);
203 BUG_ON(ret);
204 } else {
205 char *ptr = (char *)di;
206 char *start = btrfs_item_ptr(leaf, path->slots[0], char);
207 btrfs_memmove(root, leaf, ptr, ptr + sub_item_len,
208 item_len - (ptr + sub_item_len - start));
209 ret = btrfs_truncate_item(trans, root, path,
210 item_len - sub_item_len);
211 BUG_ON(ret);
212 }
213 return 0;
214}
215