xattr support for btrfs-progs
[platform/upstream/btrfs-progs.git] / 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 <stdio.h>
20 #include <stdlib.h>
21 #include "kerncompat.h"
22 #include "radix-tree.h"
23 #include "ctree.h"
24 #include "disk-io.h"
25 #include "hash.h"
26 #include "transaction.h"
27
28 static struct btrfs_dir_item *insert_with_overflow(struct
29                                                    btrfs_trans_handle *trans,
30                                                    struct btrfs_root *root,
31                                                    struct btrfs_path *path,
32                                                    struct btrfs_key *cpu_key,
33                                                    u32 data_size)
34 {
35         int ret;
36         char *ptr;
37         struct btrfs_item *item;
38         struct btrfs_leaf *leaf;
39
40         ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
41         if (ret == -EEXIST) {
42                 ret = btrfs_extend_item(trans, root, path, data_size);
43                 BUG_ON(ret > 0);
44                 if (ret)
45                         return NULL;
46         }
47         BUG_ON(ret > 0);
48         leaf = &path->nodes[0]->leaf;
49         item = leaf->items + path->slots[0];
50         ptr = btrfs_item_ptr(leaf, path->slots[0], char);
51         BUG_ON(data_size > btrfs_item_size(item));
52         ptr += btrfs_item_size(item) - data_size;
53         return (struct btrfs_dir_item *)ptr;
54 }
55
56 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
57                           *root, char *name, int name_len, u64 dir,
58                           struct btrfs_key *location, u8 type)
59 {
60         int ret = 0;
61         struct btrfs_path path;
62         struct btrfs_dir_item *dir_item;
63         char *name_ptr;
64         struct btrfs_key key;
65         u32 data_size;
66
67         key.objectid = dir;
68         btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
69         if (name_len == 1 && *name == '.')
70                 key.offset = 1;
71         else if (name_len == 2 && name[0] == '.' && name[1] == '.')
72                 key.offset = 2;
73         else
74                 ret = btrfs_name_hash(name, name_len, &key.offset);
75         BUG_ON(ret);
76         btrfs_init_path(&path);
77         data_size = sizeof(*dir_item) + name_len;
78         dir_item = insert_with_overflow(trans, root, &path, &key, data_size);
79         if (!dir_item) {
80                 ret = -1;
81                 goto out;
82         }
83         btrfs_cpu_key_to_disk(&dir_item->location, location);
84         btrfs_set_dir_type(dir_item, type);
85         btrfs_set_dir_name_len(dir_item, name_len);
86         btrfs_set_dir_data_len(dir_item, 0);
87         name_ptr = (char *)(dir_item + 1);
88         memcpy(name_ptr, name, name_len);
89
90         /* FIXME, use some real flag for selecting the extra index */
91         if (root == root->fs_info->tree_root)
92                 goto out;
93
94         btrfs_release_path(root, &path);
95         btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
96         key.offset = location->objectid;
97         dir_item = insert_with_overflow(trans, root, &path, &key, data_size);
98         if (!dir_item) {
99                 ret = -1;
100                 goto out;
101         }
102         btrfs_cpu_key_to_disk(&dir_item->location, location);
103         btrfs_set_dir_type(dir_item, type);
104         btrfs_set_dir_name_len(dir_item, name_len);
105         btrfs_set_dir_data_len(dir_item, 0);
106         name_ptr = (char *)(dir_item + 1);
107         memcpy(name_ptr, name, name_len);
108 out:
109         btrfs_release_path(root, &path);
110         return ret;
111 }
112
113 int btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
114                           *root, struct btrfs_path *path, u64 dir, char *name,
115                           int name_len, int mod)
116 {
117         int ret;
118         struct btrfs_key key;
119         int ins_len = mod < 0 ? -1 : 0;
120         int cow = mod != 0;
121
122         key.objectid = dir;
123         btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
124         ret = btrfs_name_hash(name, name_len, &key.offset);
125         BUG_ON(ret);
126         ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
127         return ret;
128 }
129
130 int btrfs_match_dir_item_name(struct btrfs_root *root,
131                               struct btrfs_path *path, char
132                               *name, int name_len)
133 {
134         struct btrfs_dir_item *dir_item;
135         char *name_ptr;
136
137         dir_item = btrfs_item_ptr(&path->nodes[0]->leaf, path->slots[0],
138                                   struct btrfs_dir_item);
139         if (btrfs_dir_name_len(dir_item) != name_len)
140                 return 0;
141         name_ptr = (char *)(dir_item + 1);
142         if (memcmp(name_ptr, name, name_len))
143                 return 0;
144         return 1;
145 }