r4313: fixed a bug in handling new xattrs in the tdb xattr backend
[samba.git] / source4 / ntvfs / posix / xattr_tdb.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    POSIX NTVFS backend - xattr support using a tdb
5
6    Copyright (C) Andrew Tridgell 2004
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "vfs_posix.h"
25
26 #define XATTR_LIST_ATTR ".xattr_list"
27
28 /*
29   we need to maintain a list of attributes on each file, so that unlink
30   can automatically clean them up
31 */
32 static NTSTATUS xattr_tdb_add_list(struct pvfs_state *pvfs, const char *attr_name, 
33                                    const char *fname, int fd)
34 {
35         DATA_BLOB blob;
36         TALLOC_CTX *mem_ctx;
37         const char *s;
38         NTSTATUS status;
39         size_t len;
40
41         if (strcmp(attr_name, XATTR_LIST_ATTR) == 0) {
42                 return NT_STATUS_OK;
43         }
44
45         mem_ctx = talloc(pvfs, 0);
46
47         status = pull_xattr_blob_tdb(pvfs, mem_ctx, XATTR_LIST_ATTR, 
48                                      fname, fd, 100, &blob);
49         if (!NT_STATUS_IS_OK(status)) {
50                 blob = data_blob(NULL, 0);
51         }
52
53         for (s=blob.data; s < (char *)(blob.data+blob.length); s += strlen(s) + 1) {
54                 if (strcmp(attr_name, s) == 0) {
55                         talloc_free(mem_ctx);
56                         return NT_STATUS_OK;
57                 }
58         }
59
60         len = strlen(attr_name) + 1;
61
62         blob.data = talloc_realloc_p(mem_ctx, blob.data, uint8_t, blob.length + len);
63         if (blob.data == NULL) {
64                 talloc_free(mem_ctx);
65                 return NT_STATUS_NO_MEMORY;             
66         }
67         memcpy(blob.data + blob.length, attr_name, len);
68         blob.length += len;
69
70         status = push_xattr_blob_tdb(pvfs, XATTR_LIST_ATTR, fname, fd, &blob);
71         talloc_free(mem_ctx);
72
73         return status;
74 }
75
76 /*
77   form a key for using in the ea_db
78 */
79 static NTSTATUS get_ea_db_key(TALLOC_CTX *mem_ctx,
80                               const char *attr_name,
81                               const char *fname, int fd, 
82                               TDB_DATA *key)
83 {
84         struct stat st;
85         size_t len = strlen(attr_name);
86
87         if (fd == -1) {
88                 if (stat(fname, &st) == -1) {
89                         return NT_STATUS_NOT_FOUND;
90                 }
91         } else {
92                 if (fstat(fd, &st) == -1) {
93                         return NT_STATUS_NOT_FOUND;
94                 }
95         }
96
97         key->dptr = talloc_array_p(mem_ctx, char, 16 + len);
98         if (key->dptr == NULL) {
99                 return NT_STATUS_NO_MEMORY;
100         }
101         key->dsize = 16 + len;
102
103         SBVAL(key->dptr, 0, st.st_dev);
104         SBVAL(key->dptr, 8, st.st_ino);
105         memcpy(key->dptr+16, attr_name, len);
106         
107         return NT_STATUS_OK;
108 }
109
110 /*
111   pull a xattr as a blob, using the ea_db tdb
112 */
113 NTSTATUS pull_xattr_blob_tdb(struct pvfs_state *pvfs,
114                              TALLOC_CTX *mem_ctx,
115                              const char *attr_name, 
116                              const char *fname, 
117                              int fd, 
118                              size_t estimated_size,
119                              DATA_BLOB *blob)
120 {
121         TDB_DATA tkey, tdata;
122         NTSTATUS status;
123
124         status = get_ea_db_key(mem_ctx, attr_name, fname, fd, &tkey);
125         if (!NT_STATUS_IS_OK(status)) {
126                 return status;
127         }
128
129         tdata = tdb_fetch(pvfs->ea_db->tdb, tkey);
130         if (tdata.dptr == NULL) {
131                 return NT_STATUS_NOT_FOUND;
132         }
133
134         *blob = data_blob_talloc(mem_ctx, tdata.dptr, tdata.dsize);
135         free(tdata.dptr);
136         if (blob->data == NULL) {
137                 return NT_STATUS_NO_MEMORY;
138         }
139
140         return NT_STATUS_OK;    
141 }
142
143 /*
144   push a xattr as a blob, using ea_db
145 */
146 NTSTATUS push_xattr_blob_tdb(struct pvfs_state *pvfs,
147                              const char *attr_name, 
148                              const char *fname, 
149                              int fd, 
150                              const DATA_BLOB *blob)
151 {
152         TDB_DATA tkey, tdata;
153         NTSTATUS status;
154
155         status = get_ea_db_key(pvfs, attr_name, fname, fd, &tkey);
156         if (!NT_STATUS_IS_OK(status)) {
157                 return status;
158         }
159         
160         tdata.dptr = blob->data;
161         tdata.dsize = blob->length;
162
163         if (tdb_chainlock(pvfs->ea_db->tdb, tkey) != 0) {
164                 talloc_free(tkey.dptr);
165                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
166         }
167
168         status = xattr_tdb_add_list(pvfs, attr_name, fname, fd);
169         if (!NT_STATUS_IS_OK(status)) {
170                 goto done;
171         }
172
173         if (tdb_store(pvfs->ea_db->tdb, tkey, tdata, TDB_REPLACE) == -1) {
174                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
175         }
176
177 done:
178         tdb_chainunlock(pvfs->ea_db->tdb, tkey);
179         talloc_free(tkey.dptr);
180         return status;  
181 }
182
183
184 /*
185   delete a xattr
186 */
187 NTSTATUS delete_xattr_tdb(struct pvfs_state *pvfs, const char *attr_name, 
188                           const char *fname, int fd)
189 {
190         TDB_DATA tkey;
191         NTSTATUS status;
192
193         status = get_ea_db_key(NULL, attr_name, fname, fd, &tkey);
194         if (!NT_STATUS_IS_OK(status)) {
195                 return status;
196         }
197         
198         if (tdb_delete(pvfs->ea_db->tdb, tkey) == -1) {
199                 talloc_free(tkey.dptr);
200                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
201         }
202
203         talloc_free(tkey.dptr);
204         return NT_STATUS_OK;    
205 }
206
207
208
209 /*
210   delete all xattrs for a file
211 */
212 NTSTATUS unlink_xattr_tdb(struct pvfs_state *pvfs, const char *fname)
213 {
214         TALLOC_CTX *mem_ctx = talloc(pvfs, 0);
215         DATA_BLOB blob;
216         const char *s;
217         NTSTATUS status;
218
219         status = pull_xattr_blob_tdb(pvfs, mem_ctx, XATTR_LIST_ATTR, 
220                                      fname, -1, 100, &blob);
221         if (!NT_STATUS_IS_OK(status)) {
222                 talloc_free(mem_ctx);
223                 return NT_STATUS_OK;
224         }
225
226         for (s=blob.data; s < (char *)(blob.data+blob.length); s += strlen(s) + 1) {
227                 delete_xattr_tdb(pvfs, s, fname, -1);
228         }
229
230         return delete_xattr_tdb(pvfs, XATTR_LIST_ATTR, fname, -1);
231 }