btrfs: Code cleanup
[safe/jmp/linux-2.6] / fs / btrfs / dir-item.c
1 /*
2  * Copyright (C) 2007 Oracle.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public
6  * License v2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public
14  * License along with this program; if not, write to the
15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16  * Boston, MA 021110-1307, USA.
17  */
18
19 #include <linux/module.h>
20 #include "ctree.h"
21 #include "disk-io.h"
22 #include "hash.h"
23 #include "transaction.h"
24
25 static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
26                                                    *trans,
27                                                    struct btrfs_root *root,
28                                                    struct btrfs_path *path,
29                                                    struct btrfs_key *cpu_key,
30                                                    u32 data_size,
31                                                    const char *name,
32                                                    int name_len)
33 {
34         int ret;
35         char *ptr;
36         struct btrfs_item *item;
37         struct btrfs_leaf *leaf;
38
39         ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
40         if (ret == -EEXIST) {
41                 struct btrfs_dir_item *di;
42                 di = btrfs_match_dir_item_name(root, path, name, name_len);
43                 if (di)
44                         return ERR_PTR(-EEXIST);
45                 ret = btrfs_extend_item(trans, root, path, data_size);
46                 WARN_ON(ret > 0);
47                 if (ret)
48                         return ERR_PTR(ret);
49         }
50         WARN_ON(ret > 0);
51         leaf = btrfs_buffer_leaf(path->nodes[0]);
52         item = leaf->items + path->slots[0];
53         ptr = btrfs_item_ptr(leaf, path->slots[0], char);
54         BUG_ON(data_size > btrfs_item_size(item));
55         ptr += btrfs_item_size(item) - data_size;
56         return (struct btrfs_dir_item *)ptr;
57 }
58
59 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
60                           *root, const char *name, int name_len, u64 dir,
61                           struct btrfs_key *location, u8 type)
62 {
63         int ret = 0;
64         int ret2 = 0;
65         struct btrfs_path *path;
66         struct btrfs_dir_item *dir_item;
67         char *name_ptr;
68         struct btrfs_key key;
69         u32 data_size;
70
71         key.objectid = dir;
72         key.flags = 0;
73         btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
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;
78         dir_item = insert_with_overflow(trans, root, path, &key, data_size,
79                                         name, name_len);
80         if (IS_ERR(dir_item)) {
81                 ret = PTR_ERR(dir_item);
82                 if (ret == -EEXIST)
83                         goto second_insert;
84                 goto out;
85         }
86
87         btrfs_cpu_key_to_disk(&dir_item->location, location);
88         btrfs_set_dir_type(dir_item, type);
89         btrfs_set_dir_flags(dir_item, 0);
90         btrfs_set_dir_name_len(dir_item, name_len);
91         name_ptr = (char *)(dir_item + 1);
92
93         btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
94         btrfs_mark_buffer_dirty(path->nodes[0]);
95
96 second_insert:
97         /* FIXME, use some real flag for selecting the extra index */
98         if (root == root->fs_info->tree_root) {
99                 ret = 0;
100                 goto out;
101         }
102         btrfs_release_path(root, path);
103
104         btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
105         key.offset = location->objectid;
106         dir_item = insert_with_overflow(trans, root, path, &key, data_size,
107                                         name, name_len);
108         if (IS_ERR(dir_item)) {
109                 ret2 = PTR_ERR(dir_item);
110                 goto out;
111         }
112         btrfs_cpu_key_to_disk(&dir_item->location, location);
113         btrfs_set_dir_type(dir_item, type);
114         btrfs_set_dir_flags(dir_item, 0);
115         btrfs_set_dir_name_len(dir_item, name_len);
116         name_ptr = (char *)(dir_item + 1);
117         btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
118         btrfs_mark_buffer_dirty(path->nodes[0]);
119 out:
120         btrfs_free_path(path);
121         if (ret)
122                 return ret;
123         if (ret2)
124                 return ret2;
125         return 0;
126 }
127
128 struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
129                                              struct btrfs_root *root,
130                                              struct btrfs_path *path, u64 dir,
131                                              const char *name, int name_len,
132                                              int mod)
133 {
134         int ret;
135         struct btrfs_key key;
136         int ins_len = mod < 0 ? -1 : 0;
137         int cow = mod != 0;
138         struct btrfs_disk_key *found_key;
139         struct btrfs_leaf *leaf;
140
141         key.objectid = dir;
142         key.flags = 0;
143         btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
144         ret = btrfs_name_hash(name, name_len, &key.offset);
145         BUG_ON(ret);
146         ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
147         if (ret < 0)
148                 return ERR_PTR(ret);
149         if (ret > 0) {
150                 if (path->slots[0] == 0)
151                         return NULL;
152                 path->slots[0]--;
153         }
154         leaf = btrfs_buffer_leaf(path->nodes[0]);
155         found_key = &leaf->items[path->slots[0]].key;
156
157         if (btrfs_disk_key_objectid(found_key) != dir ||
158             btrfs_disk_key_type(found_key) != BTRFS_DIR_ITEM_KEY ||
159             btrfs_disk_key_offset(found_key) != key.offset)
160                 return NULL;
161
162         return btrfs_match_dir_item_name(root, path, name, name_len);
163 }
164
165 struct btrfs_dir_item *
166 btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
167                             struct btrfs_root *root,
168                             struct btrfs_path *path, u64 dir,
169                             u64 objectid, const char *name, int name_len,
170                             int mod)
171 {
172         int ret;
173         struct btrfs_key key;
174         int ins_len = mod < 0 ? -1 : 0;
175         int cow = mod != 0;
176
177         key.objectid = dir;
178         key.flags = 0;
179         btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
180         key.offset = objectid;
181
182         ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
183         if (ret < 0)
184                 return ERR_PTR(ret);
185         if (ret > 0)
186                 return ERR_PTR(-ENOENT);
187         return btrfs_match_dir_item_name(root, path, name, name_len);
188 }
189
190 struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
191                               struct btrfs_path *path,
192                               const char *name, int name_len)
193 {
194         struct btrfs_dir_item *dir_item;
195         char *name_ptr;
196         u32 total_len;
197         u32 cur = 0;
198         u32 this_len;
199         struct btrfs_leaf *leaf;
200
201         leaf = btrfs_buffer_leaf(path->nodes[0]);
202         dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
203         total_len = btrfs_item_size(leaf->items + path->slots[0]);
204         while(cur < total_len) {
205                 this_len = sizeof(*dir_item) + btrfs_dir_name_len(dir_item);
206                 name_ptr = (char *)(dir_item + 1);
207
208                 if (btrfs_dir_name_len(dir_item) == name_len &&
209                     memcmp(name_ptr, name, name_len) == 0)
210                         return dir_item;
211
212                 cur += this_len;
213                 dir_item = (struct btrfs_dir_item *)((char *)dir_item +
214                                                      this_len);
215         }
216         return NULL;
217 }
218
219 int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
220                               struct btrfs_root *root,
221                               struct btrfs_path *path,
222                               struct btrfs_dir_item *di)
223 {
224
225         struct btrfs_leaf *leaf;
226         u32 sub_item_len;
227         u32 item_len;
228         int ret;
229
230         leaf = btrfs_buffer_leaf(path->nodes[0]);
231         sub_item_len = sizeof(*di) + btrfs_dir_name_len(di);
232         item_len = btrfs_item_size(leaf->items + path->slots[0]);
233         if (sub_item_len == btrfs_item_size(leaf->items + path->slots[0])) {
234                 ret = btrfs_del_item(trans, root, path);
235                 BUG_ON(ret);
236         } else {
237                 char *ptr = (char *)di;
238                 char *start = btrfs_item_ptr(leaf, path->slots[0], char);
239                 btrfs_memmove(root, leaf, ptr, ptr + sub_item_len,
240                         item_len - (ptr + sub_item_len - start));
241                 ret = btrfs_truncate_item(trans, root, path,
242                                           item_len - sub_item_len);
243                 BUG_ON(ret);
244         }
245         return 0;
246 }
247