]> rtime.felk.cvut.cz Git - linux-imx.git/blob - fs/btrfs/dir-item.c
Btrfs: trivial include fixups
[linux-imx.git] / 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 "ctree.h"
20 #include "disk-io.h"
21 #include "hash.h"
22 #include "transaction.h"
23
24 static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
25                                                    *trans,
26                                                    struct btrfs_root *root,
27                                                    struct btrfs_path *path,
28                                                    struct btrfs_key *cpu_key,
29                                                    u32 data_size,
30                                                    const char *name,
31                                                    int name_len)
32 {
33         int ret;
34         char *ptr;
35         struct btrfs_item *item;
36         struct btrfs_leaf *leaf;
37
38         ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
39         if (ret == -EEXIST) {
40                 struct btrfs_dir_item *di;
41                 di = btrfs_match_dir_item_name(root, path, name, name_len);
42                 if (di)
43                         return ERR_PTR(-EEXIST);
44                 ret = btrfs_extend_item(trans, root, path, data_size);
45                 WARN_ON(ret > 0);
46                 if (ret)
47                         return ERR_PTR(ret);
48         }
49         if (ret < 0)
50                 return ERR_PTR(ret);
51         WARN_ON(ret > 0);
52         leaf = btrfs_buffer_leaf(path->nodes[0]);
53         item = leaf->items + path->slots[0];
54         ptr = btrfs_item_ptr(leaf, path->slots[0], char);
55         BUG_ON(data_size > btrfs_item_size(item));
56         ptr += btrfs_item_size(item) - data_size;
57         return (struct btrfs_dir_item *)ptr;
58 }
59
60 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
61                           *root, const char *name, int name_len, u64 dir,
62                           struct btrfs_key *location, u8 type)
63 {
64         int ret = 0;
65         int ret2 = 0;
66         struct btrfs_path *path;
67         struct btrfs_dir_item *dir_item;
68         char *name_ptr;
69         struct btrfs_key key;
70         u32 data_size;
71
72         key.objectid = dir;
73         key.flags = 0;
74         btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
75         ret = btrfs_name_hash(name, name_len, &key.offset);
76         BUG_ON(ret);
77         path = btrfs_alloc_path();
78         data_size = sizeof(*dir_item) + name_len;
79         dir_item = insert_with_overflow(trans, root, path, &key, data_size,
80                                         name, name_len);
81         if (IS_ERR(dir_item)) {
82                 ret = PTR_ERR(dir_item);
83                 if (ret == -EEXIST)
84                         goto second_insert;
85                 goto out;
86         }
87
88         btrfs_cpu_key_to_disk(&dir_item->location, location);
89         btrfs_set_dir_type(dir_item, type);
90         btrfs_set_dir_flags(dir_item, 0);
91         btrfs_set_dir_name_len(dir_item, name_len);
92         name_ptr = (char *)(dir_item + 1);
93
94         btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
95         btrfs_mark_buffer_dirty(path->nodes[0]);
96
97 second_insert:
98         /* FIXME, use some real flag for selecting the extra index */
99         if (root == root->fs_info->tree_root) {
100                 ret = 0;
101                 goto out;
102         }
103         btrfs_release_path(root, path);
104
105         btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
106         key.offset = location->objectid;
107         dir_item = insert_with_overflow(trans, root, path, &key, data_size,
108                                         name, name_len);
109         if (IS_ERR(dir_item)) {
110                 ret2 = PTR_ERR(dir_item);
111                 goto out;
112         }
113         btrfs_cpu_key_to_disk(&dir_item->location, location);
114         btrfs_set_dir_type(dir_item, type);
115         btrfs_set_dir_flags(dir_item, 0);
116         btrfs_set_dir_name_len(dir_item, name_len);
117         name_ptr = (char *)(dir_item + 1);
118         btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
119         btrfs_mark_buffer_dirty(path->nodes[0]);
120 out:
121         btrfs_free_path(path);
122         if (ret)
123                 return ret;
124         if (ret2)
125                 return ret2;
126         return 0;
127 }
128
129 struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
130                                              struct btrfs_root *root,
131                                              struct btrfs_path *path, u64 dir,
132                                              const char *name, int name_len,
133                                              int mod)
134 {
135         int ret;
136         struct btrfs_key key;
137         int ins_len = mod < 0 ? -1 : 0;
138         int cow = mod != 0;
139         struct btrfs_disk_key *found_key;
140         struct btrfs_leaf *leaf;
141
142         key.objectid = dir;
143         key.flags = 0;
144         btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
145         ret = btrfs_name_hash(name, name_len, &key.offset);
146         BUG_ON(ret);
147         ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
148         if (ret < 0)
149                 return ERR_PTR(ret);
150         if (ret > 0) {
151                 if (path->slots[0] == 0)
152                         return NULL;
153                 path->slots[0]--;
154         }
155         leaf = btrfs_buffer_leaf(path->nodes[0]);
156         found_key = &leaf->items[path->slots[0]].key;
157
158         if (btrfs_disk_key_objectid(found_key) != dir ||
159             btrfs_disk_key_type(found_key) != BTRFS_DIR_ITEM_KEY ||
160             btrfs_disk_key_offset(found_key) != key.offset)
161                 return NULL;
162
163         return btrfs_match_dir_item_name(root, path, name, name_len);
164 }
165
166 struct btrfs_dir_item *
167 btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans,
168                             struct btrfs_root *root,
169                             struct btrfs_path *path, u64 dir,
170                             u64 objectid, const char *name, int name_len,
171                             int mod)
172 {
173         int ret;
174         struct btrfs_key key;
175         int ins_len = mod < 0 ? -1 : 0;
176         int cow = mod != 0;
177
178         key.objectid = dir;
179         key.flags = 0;
180         btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
181         key.offset = objectid;
182
183         ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
184         if (ret < 0)
185                 return ERR_PTR(ret);
186         if (ret > 0)
187                 return ERR_PTR(-ENOENT);
188         return btrfs_match_dir_item_name(root, path, name, name_len);
189 }
190
191 struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
192                               struct btrfs_path *path,
193                               const char *name, int name_len)
194 {
195         struct btrfs_dir_item *dir_item;
196         char *name_ptr;
197         u32 total_len;
198         u32 cur = 0;
199         u32 this_len;
200         struct btrfs_leaf *leaf;
201
202         leaf = btrfs_buffer_leaf(path->nodes[0]);
203         dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
204         total_len = btrfs_item_size(leaf->items + path->slots[0]);
205         while(cur < total_len) {
206                 this_len = sizeof(*dir_item) + btrfs_dir_name_len(dir_item);
207                 name_ptr = (char *)(dir_item + 1);
208
209                 if (btrfs_dir_name_len(dir_item) == name_len &&
210                     memcmp(name_ptr, name, name_len) == 0)
211                         return dir_item;
212
213                 cur += this_len;
214                 dir_item = (struct btrfs_dir_item *)((char *)dir_item +
215                                                      this_len);
216         }
217         return NULL;
218 }
219
220 int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
221                               struct btrfs_root *root,
222                               struct btrfs_path *path,
223                               struct btrfs_dir_item *di)
224 {
225
226         struct btrfs_leaf *leaf;
227         u32 sub_item_len;
228         u32 item_len;
229         int ret = 0;
230
231         leaf = btrfs_buffer_leaf(path->nodes[0]);
232         sub_item_len = sizeof(*di) + btrfs_dir_name_len(di);
233         item_len = btrfs_item_size(leaf->items + path->slots[0]);
234         if (sub_item_len == btrfs_item_size(leaf->items + path->slots[0])) {
235                 ret = btrfs_del_item(trans, root, path);
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         }
244         return 0;
245 }
246