s3-xattr_tdb: make xattr_tdb a private library, for use outside vfs_xattr_tdb
[samba.git] / source3 / modules / vfs_xattr_tdb.c
1 /*
2  * Store posix-level xattrs in a tdb
3  *
4  * Copyright (C) Volker Lendecke, 2007
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "system/filesys.h"
22 #include "smbd/smbd.h"
23 #include "dbwrap/dbwrap.h"
24 #include "dbwrap/dbwrap_open.h"
25 #include "source3/lib/xattr_tdb.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_VFS
29
30 static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle,
31                                   const char *path, const char *name,
32                                   void *value, size_t size)
33 {
34         SMB_STRUCT_STAT sbuf;
35         struct file_id id;
36         struct db_context *db;
37
38         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
39
40         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
41                 return -1;
42         }
43
44         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
45
46         return xattr_tdb_getattr(db, &id, name, value, size);
47 }
48
49 static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
50                                    struct files_struct *fsp,
51                                    const char *name, void *value, size_t size)
52 {
53         SMB_STRUCT_STAT sbuf;
54         struct file_id id;
55         struct db_context *db;
56
57         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
58
59         if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
60                 return -1;
61         }
62
63         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
64
65         return xattr_tdb_getattr(db, &id, name, value, size);
66 }
67
68 static int xattr_tdb_setxattr(struct vfs_handle_struct *handle,
69                               const char *path, const char *name,
70                               const void *value, size_t size, int flags)
71 {
72         SMB_STRUCT_STAT sbuf;
73         struct file_id id;
74         struct db_context *db;
75
76         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
77
78         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
79                 return -1;
80         }
81
82         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
83
84         return xattr_tdb_setattr(db, &id, name, value, size, flags);
85 }
86
87 static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
88                                struct files_struct *fsp,
89                                const char *name, const void *value,
90                                size_t size, int flags)
91 {
92         SMB_STRUCT_STAT sbuf;
93         struct file_id id;
94         struct db_context *db;
95
96         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
97
98         if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
99                 return -1;
100         }
101
102         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
103
104         return xattr_tdb_setattr(db, &id, name, value, size, flags);
105 }
106
107 static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle,
108                                    const char *path, char *list, size_t size)
109 {
110         SMB_STRUCT_STAT sbuf;
111         struct file_id id;
112         struct db_context *db;
113
114         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
115
116         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
117                 return -1;
118         }
119
120         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
121
122         return xattr_tdb_listattr(db, &id, list, size);
123 }
124
125 static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
126                                     struct files_struct *fsp, char *list,
127                                     size_t size)
128 {
129         SMB_STRUCT_STAT sbuf;
130         struct file_id id;
131         struct db_context *db;
132
133         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
134
135         if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
136                 return -1;
137         }
138
139         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
140
141         return xattr_tdb_listattr(db, &id, list, size);
142 }
143
144 static int xattr_tdb_removexattr(struct vfs_handle_struct *handle,
145                                  const char *path, const char *name)
146 {
147         SMB_STRUCT_STAT sbuf;
148         struct file_id id;
149         struct db_context *db;
150
151         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
152
153         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
154                 return -1;
155         }
156
157         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
158
159         return xattr_tdb_removeattr(db, &id, name);
160 }
161
162 static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
163                                   struct files_struct *fsp, const char *name)
164 {
165         SMB_STRUCT_STAT sbuf;
166         struct file_id id;
167         struct db_context *db;
168
169         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
170
171         if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
172                 return -1;
173         }
174
175         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
176
177         return xattr_tdb_removeattr(db, &id, name);
178 }
179
180 /*
181  * Open the tdb file upon VFS_CONNECT
182  */
183
184 static bool xattr_tdb_init(int snum, struct db_context **p_db)
185 {
186         struct db_context *db;
187         const char *dbname;
188         char *def_dbname;
189
190         def_dbname = state_path("xattr.tdb");
191         if (def_dbname == NULL) {
192                 errno = ENOSYS;
193                 return false;
194         }
195
196         dbname = lp_parm_const_string(snum, "xattr_tdb", "file", def_dbname);
197
198         /* now we know dbname is not NULL */
199
200         become_root();
201         db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
202                      DBWRAP_LOCK_ORDER_2);
203         unbecome_root();
204
205         if (db == NULL) {
206 #if defined(ENOTSUP)
207                 errno = ENOTSUP;
208 #else
209                 errno = ENOSYS;
210 #endif
211                 TALLOC_FREE(def_dbname);
212                 return false;
213         }
214
215         *p_db = db;
216         TALLOC_FREE(def_dbname);
217         return true;
218 }
219
220 /*
221  * On unlink we need to delete the tdb record
222  */
223 static int xattr_tdb_unlink(vfs_handle_struct *handle,
224                             const struct smb_filename *smb_fname)
225 {
226         struct smb_filename *smb_fname_tmp = NULL;
227         struct file_id id;
228         struct db_context *db;
229         NTSTATUS status;
230         int ret = -1;
231         bool remove_record = false;
232
233         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
234
235         status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
236         if (!NT_STATUS_IS_OK(status)) {
237                 errno = map_errno_from_nt_status(status);
238                 return -1;
239         }
240
241         if (lp_posix_pathnames()) {
242                 ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
243         } else {
244                 ret = SMB_VFS_STAT(handle->conn, smb_fname_tmp);
245         }
246         if (ret == -1) {
247                 goto out;
248         }
249
250         if (smb_fname_tmp->st.st_ex_nlink == 1) {
251                 /* Only remove record on last link to file. */
252                 remove_record = true;
253         }
254
255         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
256
257         if (ret == -1) {
258                 goto out;
259         }
260
261         if (!remove_record) {
262                 goto out;
263         }
264
265         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &smb_fname_tmp->st);
266
267         xattr_tdb_remove_all_attrs(db, &id);
268
269  out:
270         TALLOC_FREE(smb_fname_tmp);
271         return ret;
272 }
273
274 /*
275  * On rmdir we need to delete the tdb record
276  */
277 static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path)
278 {
279         SMB_STRUCT_STAT sbuf;
280         struct file_id id;
281         struct db_context *db;
282         int ret;
283
284         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
285
286         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
287                 return -1;
288         }
289
290         ret = SMB_VFS_NEXT_RMDIR(handle, path);
291
292         if (ret == -1) {
293                 return -1;
294         }
295
296         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
297
298         xattr_tdb_remove_all_attrs(db, &id);
299
300         return 0;
301 }
302
303 /*
304  * Destructor for the VFS private data
305  */
306
307 static void close_xattr_db(void **data)
308 {
309         struct db_context **p_db = (struct db_context **)data;
310         TALLOC_FREE(*p_db);
311 }
312
313 static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
314                           const char *user)
315 {
316         char *sname = NULL;
317         int res, snum;
318         struct db_context *db;
319
320         res = SMB_VFS_NEXT_CONNECT(handle, service, user);
321         if (res < 0) {
322                 return res;
323         }
324
325         snum = find_service(talloc_tos(), service, &sname);
326         if (snum == -1 || sname == NULL) {
327                 /*
328                  * Should not happen, but we should not fail just *here*.
329                  */
330                 return 0;
331         }
332
333         if (!xattr_tdb_init(snum, &db)) {
334                 DEBUG(5, ("Could not init xattr tdb\n"));
335                 lp_do_parameter(snum, "ea support", "False");
336                 return 0;
337         }
338
339         lp_do_parameter(snum, "ea support", "True");
340
341         SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
342                                 struct db_context, return -1);
343
344         return 0;
345 }
346
347 static struct vfs_fn_pointers vfs_xattr_tdb_fns = {
348         .getxattr_fn = xattr_tdb_getxattr,
349         .fgetxattr_fn = xattr_tdb_fgetxattr,
350         .setxattr_fn = xattr_tdb_setxattr,
351         .fsetxattr_fn = xattr_tdb_fsetxattr,
352         .listxattr_fn = xattr_tdb_listxattr,
353         .flistxattr_fn = xattr_tdb_flistxattr,
354         .removexattr_fn = xattr_tdb_removexattr,
355         .fremovexattr_fn = xattr_tdb_fremovexattr,
356         .unlink_fn = xattr_tdb_unlink,
357         .rmdir_fn = xattr_tdb_rmdir,
358         .connect_fn = xattr_tdb_connect,
359 };
360
361 NTSTATUS vfs_xattr_tdb_init(void);
362 NTSTATUS vfs_xattr_tdb_init(void)
363 {
364         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb",
365                                 &vfs_xattr_tdb_fns);
366 }