2 * Store posix-level xattrs in a tdb
4 * Copyright (C) Volker Lendecke, 2007
5 * Copyright (C) Andrew Bartlett, 2012
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "system/filesys.h"
23 #include "smbd/smbd.h"
24 #include "dbwrap/dbwrap.h"
25 #include "dbwrap/dbwrap_open.h"
26 #include "source3/lib/xattr_tdb.h"
29 #define DBGC_CLASS DBGC_VFS
31 static bool xattr_tdb_init(int snum
, TALLOC_CTX
*mem_ctx
, struct db_context
**p_db
);
33 static int xattr_tdb_get_file_id(struct vfs_handle_struct
*handle
,
34 const char *path
, struct file_id
*id
)
37 TALLOC_CTX
*frame
= talloc_stackframe();
38 struct smb_filename
*smb_fname
= NULL
;
39 NTSTATUS status
= create_synthetic_smb_fname_split(frame
, path
, NULL
,
41 if (!NT_STATUS_IS_OK(status
)) {
42 errno
= map_errno_from_nt_status(status
);
47 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
54 *id
= SMB_VFS_NEXT_FILE_ID_CREATE(handle
, &smb_fname
->st
);
59 static ssize_t
xattr_tdb_getxattr(struct vfs_handle_struct
*handle
,
60 const char *path
, const char *name
,
61 void *value
, size_t size
)
64 struct db_context
*db
;
68 TALLOC_CTX
*frame
= talloc_stackframe();
70 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
71 if (!xattr_tdb_init(-1, frame
, &db
))
73 TALLOC_FREE(frame
); return -1;
76 ret
= xattr_tdb_get_file_id(handle
, path
, &id
);
82 xattr_size
= xattr_tdb_getattr(db
, frame
, &id
, name
, &blob
);
88 if (blob
.length
> size
) {
93 memcpy(value
, blob
.data
, xattr_size
);
98 static ssize_t
xattr_tdb_fgetxattr(struct vfs_handle_struct
*handle
,
99 struct files_struct
*fsp
,
100 const char *name
, void *value
, size_t size
)
102 SMB_STRUCT_STAT sbuf
;
104 struct db_context
*db
;
107 TALLOC_CTX
*frame
= talloc_stackframe();
109 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
110 if (!xattr_tdb_init(-1, frame
, &db
))
112 TALLOC_FREE(frame
); return -1;
115 if (SMB_VFS_NEXT_FSTAT(handle
, fsp
, &sbuf
) == -1) {
120 id
= SMB_VFS_NEXT_FILE_ID_CREATE(handle
, &sbuf
);
122 xattr_size
= xattr_tdb_getattr(db
, frame
, &id
, name
, &blob
);
123 if (xattr_size
< 0) {
128 if (blob
.length
> size
) {
133 memcpy(value
, blob
.data
, xattr_size
);
138 static int xattr_tdb_setxattr(struct vfs_handle_struct
*handle
,
139 const char *path
, const char *name
,
140 const void *value
, size_t size
, int flags
)
143 struct db_context
*db
;
145 TALLOC_CTX
*frame
= talloc_stackframe();
147 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
148 if (!xattr_tdb_init(-1, frame
, &db
))
150 TALLOC_FREE(frame
); return -1;
153 ret
= xattr_tdb_get_file_id(handle
, path
, &id
);
159 ret
= xattr_tdb_setattr(db
, &id
, name
, value
, size
, flags
);
164 static int xattr_tdb_fsetxattr(struct vfs_handle_struct
*handle
,
165 struct files_struct
*fsp
,
166 const char *name
, const void *value
,
167 size_t size
, int flags
)
169 SMB_STRUCT_STAT sbuf
;
171 struct db_context
*db
;
173 TALLOC_CTX
*frame
= talloc_stackframe();
175 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
176 if (!xattr_tdb_init(-1, frame
, &db
))
178 TALLOC_FREE(frame
); return -1;
181 if (SMB_VFS_NEXT_FSTAT(handle
, fsp
, &sbuf
) == -1) {
186 id
= SMB_VFS_NEXT_FILE_ID_CREATE(handle
, &sbuf
);
188 ret
= xattr_tdb_setattr(db
, &id
, name
, value
, size
, flags
);
194 static ssize_t
xattr_tdb_listxattr(struct vfs_handle_struct
*handle
,
195 const char *path
, char *list
, size_t size
)
198 struct db_context
*db
;
200 TALLOC_CTX
*frame
= talloc_stackframe();
202 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
203 if (!xattr_tdb_init(-1, frame
, &db
))
205 TALLOC_FREE(frame
); return -1;
208 ret
= xattr_tdb_get_file_id(handle
, path
, &id
);
214 ret
= xattr_tdb_listattr(db
, &id
, list
, size
);
220 static ssize_t
xattr_tdb_flistxattr(struct vfs_handle_struct
*handle
,
221 struct files_struct
*fsp
, char *list
,
224 SMB_STRUCT_STAT sbuf
;
226 struct db_context
*db
;
228 TALLOC_CTX
*frame
= talloc_stackframe();
230 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
231 if (!xattr_tdb_init(-1, frame
, &db
))
233 TALLOC_FREE(frame
); return -1;
236 if (SMB_VFS_NEXT_FSTAT(handle
, fsp
, &sbuf
) == -1) {
241 id
= SMB_VFS_NEXT_FILE_ID_CREATE(handle
, &sbuf
);
243 ret
= xattr_tdb_listattr(db
, &id
, list
, size
);
248 static int xattr_tdb_removexattr(struct vfs_handle_struct
*handle
,
249 const char *path
, const char *name
)
252 struct db_context
*db
;
254 TALLOC_CTX
*frame
= talloc_stackframe();
256 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
257 if (!xattr_tdb_init(-1, frame
, &db
))
259 TALLOC_FREE(frame
); return -1;
262 ret
= xattr_tdb_get_file_id(handle
, path
, &id
);
269 ret
= xattr_tdb_removeattr(db
, &id
, name
);
274 static int xattr_tdb_fremovexattr(struct vfs_handle_struct
*handle
,
275 struct files_struct
*fsp
, const char *name
)
277 SMB_STRUCT_STAT sbuf
;
279 struct db_context
*db
;
281 TALLOC_CTX
*frame
= talloc_stackframe();
283 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
284 if (!xattr_tdb_init(-1, frame
, &db
))
286 TALLOC_FREE(frame
); return -1;
289 if (SMB_VFS_NEXT_FSTAT(handle
, fsp
, &sbuf
) == -1) {
294 id
= SMB_VFS_NEXT_FILE_ID_CREATE(handle
, &sbuf
);
296 ret
= xattr_tdb_removeattr(db
, &id
, name
);
302 * Open the tdb file upon VFS_CONNECT
305 static bool xattr_tdb_init(int snum
, TALLOC_CTX
*mem_ctx
, struct db_context
**p_db
)
307 struct db_context
*db
;
311 def_dbname
= state_path("xattr.tdb");
312 if (def_dbname
== NULL
) {
317 dbname
= lp_parm_const_string(snum
, "xattr_tdb", "file", def_dbname
);
319 /* now we know dbname is not NULL */
322 db
= db_open(NULL
, dbname
, 0, TDB_DEFAULT
, O_RDWR
|O_CREAT
, 0600,
323 DBWRAP_LOCK_ORDER_2
);
332 TALLOC_FREE(def_dbname
);
337 TALLOC_FREE(def_dbname
);
342 * On unlink we need to delete the tdb record
344 static int xattr_tdb_unlink(vfs_handle_struct
*handle
,
345 const struct smb_filename
*smb_fname
)
347 struct smb_filename
*smb_fname_tmp
= NULL
;
349 struct db_context
*db
;
352 bool remove_record
= false;
353 TALLOC_CTX
*frame
= talloc_stackframe();
355 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
356 if (!xattr_tdb_init(-1, frame
, &db
))
358 TALLOC_FREE(frame
); return -1;
361 status
= copy_smb_filename(frame
, smb_fname
, &smb_fname_tmp
);
362 if (!NT_STATUS_IS_OK(status
)) {
364 errno
= map_errno_from_nt_status(status
);
368 if (lp_posix_pathnames()) {
369 ret
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname_tmp
);
371 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname_tmp
);
377 if (smb_fname_tmp
->st
.st_ex_nlink
== 1) {
378 /* Only remove record on last link to file. */
379 remove_record
= true;
382 ret
= SMB_VFS_NEXT_UNLINK(handle
, smb_fname_tmp
);
388 if (!remove_record
) {
392 id
= SMB_VFS_NEXT_FILE_ID_CREATE(handle
, &smb_fname_tmp
->st
);
394 xattr_tdb_remove_all_attrs(db
, &id
);
402 * On rmdir we need to delete the tdb record
404 static int xattr_tdb_rmdir(vfs_handle_struct
*handle
, const char *path
)
406 SMB_STRUCT_STAT sbuf
;
408 struct db_context
*db
;
410 TALLOC_CTX
*frame
= talloc_stackframe();
412 SMB_VFS_HANDLE_GET_DATA(handle
, db
, struct db_context
,
413 if (!xattr_tdb_init(-1, frame
, &db
))
415 TALLOC_FREE(frame
); return -1;
418 if (vfs_stat_smb_fname(handle
->conn
, path
, &sbuf
) == -1) {
423 ret
= SMB_VFS_NEXT_RMDIR(handle
, path
);
430 id
= SMB_VFS_NEXT_FILE_ID_CREATE(handle
, &sbuf
);
432 xattr_tdb_remove_all_attrs(db
, &id
);
439 * Destructor for the VFS private data
442 static void close_xattr_db(void **data
)
444 struct db_context
**p_db
= (struct db_context
**)data
;
448 static int xattr_tdb_connect(vfs_handle_struct
*handle
, const char *service
,
453 struct db_context
*db
;
455 res
= SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
460 snum
= find_service(talloc_tos(), service
, &sname
);
461 if (snum
== -1 || sname
== NULL
) {
463 * Should not happen, but we should not fail just *here*.
468 if (!xattr_tdb_init(snum
, NULL
, &db
)) {
469 DEBUG(5, ("Could not init xattr tdb\n"));
470 lp_do_parameter(snum
, "ea support", "False");
474 lp_do_parameter(snum
, "ea support", "True");
476 SMB_VFS_HANDLE_SET_DATA(handle
, db
, close_xattr_db
,
477 struct db_context
, return -1);
482 static struct vfs_fn_pointers vfs_xattr_tdb_fns
= {
483 .getxattr_fn
= xattr_tdb_getxattr
,
484 .fgetxattr_fn
= xattr_tdb_fgetxattr
,
485 .setxattr_fn
= xattr_tdb_setxattr
,
486 .fsetxattr_fn
= xattr_tdb_fsetxattr
,
487 .listxattr_fn
= xattr_tdb_listxattr
,
488 .flistxattr_fn
= xattr_tdb_flistxattr
,
489 .removexattr_fn
= xattr_tdb_removexattr
,
490 .fremovexattr_fn
= xattr_tdb_fremovexattr
,
491 .unlink_fn
= xattr_tdb_unlink
,
492 .rmdir_fn
= xattr_tdb_rmdir
,
493 .connect_fn
= xattr_tdb_connect
,
496 NTSTATUS
vfs_xattr_tdb_init(void);
497 NTSTATUS
vfs_xattr_tdb_init(void)
499 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "xattr_tdb",