s3-vfs: Set errno in xattr emulation
[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         ssize_t xattr_size;
38         DATA_BLOB blob;
39         TALLOC_CTX *frame = talloc_stackframe();
40
41         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
42                                 TALLOC_FREE(frame); return -1);
43
44         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
45                 TALLOC_FREE(frame);
46                 return -1;
47         }
48
49         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
50
51         xattr_size = xattr_tdb_getattr(db, frame, &id, name, &blob);
52         if (xattr_size < 0) {
53                 errno = ENOATTR;
54                 TALLOC_FREE(frame);
55                 return -1;
56         }
57         if (blob.length > size) {
58                 TALLOC_FREE(frame);
59                 errno = ERANGE;
60                 return -1;
61         }
62         memcpy(value, blob.data, xattr_size);
63         TALLOC_FREE(frame);
64         return xattr_size;
65 }
66
67 static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
68                                    struct files_struct *fsp,
69                                    const char *name, void *value, size_t size)
70 {
71         SMB_STRUCT_STAT sbuf;
72         struct file_id id;
73         struct db_context *db;
74         ssize_t xattr_size;
75         DATA_BLOB blob;
76         TALLOC_CTX *frame = talloc_stackframe();
77
78         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, TALLOC_FREE(frame); return -1);
79
80         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
81                 TALLOC_FREE(frame);
82                 return -1;
83         }
84
85         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
86
87         xattr_size = xattr_tdb_getattr(db, frame, &id, name, &blob);
88         if (xattr_size < 0) {
89                 errno = ENOATTR;
90                 TALLOC_FREE(frame);
91                 return -1;
92         }
93         if (blob.length > size) {
94                 TALLOC_FREE(frame);
95                 errno = ERANGE;
96                 return -1;
97         }
98         memcpy(value, blob.data, xattr_size);
99         TALLOC_FREE(frame);
100         return xattr_size;
101 }
102
103 static int xattr_tdb_setxattr(struct vfs_handle_struct *handle,
104                               const char *path, const char *name,
105                               const void *value, size_t size, int flags)
106 {
107         SMB_STRUCT_STAT sbuf;
108         struct file_id id;
109         struct db_context *db;
110
111         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
112
113         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
114                 return -1;
115         }
116
117         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
118
119         return xattr_tdb_setattr(db, &id, name, value, size, flags);
120 }
121
122 static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
123                                struct files_struct *fsp,
124                                const char *name, const void *value,
125                                size_t size, int flags)
126 {
127         SMB_STRUCT_STAT sbuf;
128         struct file_id id;
129         struct db_context *db;
130
131         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
132
133         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
134                 return -1;
135         }
136
137         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
138
139         return xattr_tdb_setattr(db, &id, name, value, size, flags);
140 }
141
142 static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle,
143                                    const char *path, char *list, size_t size)
144 {
145         SMB_STRUCT_STAT sbuf;
146         struct file_id id;
147         struct db_context *db;
148
149         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
150
151         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
152                 return -1;
153         }
154
155         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
156
157         return xattr_tdb_listattr(db, &id, list, size);
158 }
159
160 static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
161                                     struct files_struct *fsp, char *list,
162                                     size_t size)
163 {
164         SMB_STRUCT_STAT sbuf;
165         struct file_id id;
166         struct db_context *db;
167
168         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
169
170         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
171                 return -1;
172         }
173
174         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
175
176         return xattr_tdb_listattr(db, &id, list, size);
177 }
178
179 static int xattr_tdb_removexattr(struct vfs_handle_struct *handle,
180                                  const char *path, const char *name)
181 {
182         SMB_STRUCT_STAT sbuf;
183         struct file_id id;
184         struct db_context *db;
185
186         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
187
188         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
189                 return -1;
190         }
191
192         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
193
194         return xattr_tdb_removeattr(db, &id, name);
195 }
196
197 static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
198                                   struct files_struct *fsp, const char *name)
199 {
200         SMB_STRUCT_STAT sbuf;
201         struct file_id id;
202         struct db_context *db;
203
204         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
205
206         if (SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf) == -1) {
207                 return -1;
208         }
209
210         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
211
212         return xattr_tdb_removeattr(db, &id, name);
213 }
214
215 /*
216  * Open the tdb file upon VFS_CONNECT
217  */
218
219 static bool xattr_tdb_init(int snum, struct db_context **p_db)
220 {
221         struct db_context *db;
222         const char *dbname;
223         char *def_dbname;
224
225         def_dbname = state_path("xattr.tdb");
226         if (def_dbname == NULL) {
227                 errno = ENOSYS;
228                 return false;
229         }
230
231         dbname = lp_parm_const_string(snum, "xattr_tdb", "file", def_dbname);
232
233         /* now we know dbname is not NULL */
234
235         become_root();
236         db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
237                      DBWRAP_LOCK_ORDER_2);
238         unbecome_root();
239
240         if (db == NULL) {
241 #if defined(ENOTSUP)
242                 errno = ENOTSUP;
243 #else
244                 errno = ENOSYS;
245 #endif
246                 TALLOC_FREE(def_dbname);
247                 return false;
248         }
249
250         *p_db = db;
251         TALLOC_FREE(def_dbname);
252         return true;
253 }
254
255 /*
256  * On unlink we need to delete the tdb record
257  */
258 static int xattr_tdb_unlink(vfs_handle_struct *handle,
259                             const struct smb_filename *smb_fname)
260 {
261         struct smb_filename *smb_fname_tmp = NULL;
262         struct file_id id;
263         struct db_context *db;
264         NTSTATUS status;
265         int ret = -1;
266         bool remove_record = false;
267
268         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
269
270         status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
271         if (!NT_STATUS_IS_OK(status)) {
272                 errno = map_errno_from_nt_status(status);
273                 return -1;
274         }
275
276         if (lp_posix_pathnames()) {
277                 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_tmp);
278         } else {
279                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_tmp);
280         }
281         if (ret == -1) {
282                 goto out;
283         }
284
285         if (smb_fname_tmp->st.st_ex_nlink == 1) {
286                 /* Only remove record on last link to file. */
287                 remove_record = true;
288         }
289
290         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
291
292         if (ret == -1) {
293                 goto out;
294         }
295
296         if (!remove_record) {
297                 goto out;
298         }
299
300         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &smb_fname_tmp->st);
301
302         xattr_tdb_remove_all_attrs(db, &id);
303
304  out:
305         TALLOC_FREE(smb_fname_tmp);
306         return ret;
307 }
308
309 /*
310  * On rmdir we need to delete the tdb record
311  */
312 static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path)
313 {
314         SMB_STRUCT_STAT sbuf;
315         struct file_id id;
316         struct db_context *db;
317         int ret;
318
319         SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
320
321         if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
322                 return -1;
323         }
324
325         ret = SMB_VFS_NEXT_RMDIR(handle, path);
326
327         if (ret == -1) {
328                 return -1;
329         }
330
331         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
332
333         xattr_tdb_remove_all_attrs(db, &id);
334
335         return 0;
336 }
337
338 /*
339  * Destructor for the VFS private data
340  */
341
342 static void close_xattr_db(void **data)
343 {
344         struct db_context **p_db = (struct db_context **)data;
345         TALLOC_FREE(*p_db);
346 }
347
348 static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
349                           const char *user)
350 {
351         char *sname = NULL;
352         int res, snum;
353         struct db_context *db;
354
355         res = SMB_VFS_NEXT_CONNECT(handle, service, user);
356         if (res < 0) {
357                 return res;
358         }
359
360         snum = find_service(talloc_tos(), service, &sname);
361         if (snum == -1 || sname == NULL) {
362                 /*
363                  * Should not happen, but we should not fail just *here*.
364                  */
365                 return 0;
366         }
367
368         if (!xattr_tdb_init(snum, &db)) {
369                 DEBUG(5, ("Could not init xattr tdb\n"));
370                 lp_do_parameter(snum, "ea support", "False");
371                 return 0;
372         }
373
374         lp_do_parameter(snum, "ea support", "True");
375
376         SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
377                                 struct db_context, return -1);
378
379         return 0;
380 }
381
382 static struct vfs_fn_pointers vfs_xattr_tdb_fns = {
383         .getxattr_fn = xattr_tdb_getxattr,
384         .fgetxattr_fn = xattr_tdb_fgetxattr,
385         .setxattr_fn = xattr_tdb_setxattr,
386         .fsetxattr_fn = xattr_tdb_fsetxattr,
387         .listxattr_fn = xattr_tdb_listxattr,
388         .flistxattr_fn = xattr_tdb_flistxattr,
389         .removexattr_fn = xattr_tdb_removexattr,
390         .fremovexattr_fn = xattr_tdb_fremovexattr,
391         .unlink_fn = xattr_tdb_unlink,
392         .rmdir_fn = xattr_tdb_rmdir,
393         .connect_fn = xattr_tdb_connect,
394 };
395
396 NTSTATUS vfs_xattr_tdb_init(void);
397 NTSTATUS vfs_xattr_tdb_init(void)
398 {
399         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb",
400                                 &vfs_xattr_tdb_fns);
401 }