2 Unix SMB/CIFS implementation.
3 Wrap disk only vfs functions to sidestep dodgy compilers.
4 Copyright (C) Tim Potter 1998
5 Copyright (C) Jeremy Allison 2007
6 Copyright (C) Brian Chrisman 2011 <bchrisman@gmail.com>
7 Copyright (C) Richard Sharpe 2011 <realrichardsharpe@gmail.com>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * This VFS only works with the libceph.so user-space client. It is not needed
25 * if you are using the kernel client or the FUSE client.
27 * Add the following smb.conf parameter to each share that will be hosted on
30 * vfs objects = ceph [any others you need go here]
34 #include "smbd/smbd.h"
36 #include <sys/statvfs.h>
37 #include "cephfs/libcephfs.h"
38 #include "smbprofile.h"
39 #include "modules/posixacl_xattr.h"
40 #include "lib/util/tevent_unix.h"
43 #define DBGC_CLASS DBGC_VFS
45 #ifndef LIBCEPHFS_VERSION
46 #define LIBCEPHFS_VERSION(maj, min, extra) ((maj << 16) + (min << 8) + extra)
47 #define LIBCEPHFS_VERSION_CODE LIBCEPHFS_VERSION(0, 0, 0)
51 * Use %llu whenever we have a 64bit unsigned int, and cast to (long long unsigned)
53 #define llu(_var) ((long long unsigned)_var)
56 * Note, libceph's return code model is to return -errno! So we have to convert
57 * to what Samba expects, with is set errno to -return and return -1
59 #define WRAP_RETURN(_res) \
68 * We mount only one file system and then all shares are assumed to be in that.
69 * FIXME: If we want to support more than one FS, then we have to deal with
72 * So, cmount tells us if we have been this way before and whether
73 * we need to mount ceph and cmount_cnt tells us how many times we have
76 static struct ceph_mount_info * cmount = NULL;
77 static uint32_t cmount_cnt = 0;
79 /* Check for NULL pointer parameters in cephwrap_* functions */
81 /* We don't want to have NULL function pointers lying around. Someone
82 is sure to try and execute them. These stubs are used to prevent
85 static int cephwrap_connect(struct vfs_handle_struct *handle, const char *service, const char *user)
89 int snum = SNUM(handle->conn);
90 const char *conf_file;
94 handle->data = cmount; /* We have been here before */
99 /* if config_file and/or user_id are NULL, ceph will use defaults */
100 conf_file = lp_parm_const_string(snum, "ceph", "config_file", NULL);
101 user_id = lp_parm_const_string(snum, "ceph", "user_id", NULL);
103 DBG_DEBUG("[CEPH] calling: ceph_create\n");
104 ret = ceph_create(&cmount, user_id);
109 DBG_DEBUG("[CEPH] calling: ceph_conf_read_file with %s\n",
110 (conf_file == NULL ? "default path" : conf_file));
111 ret = ceph_conf_read_file(cmount, conf_file);
116 DBG_DEBUG("[CEPH] calling: ceph_conf_get\n");
117 ret = ceph_conf_get(cmount, "log file", buf, sizeof(buf));
122 DBG_DEBUG("[CEPH] calling: ceph_mount\n");
123 ret = ceph_mount(cmount, NULL);
129 * encode mount context/state into our vfs/connection holding structure
130 * cmount is a ceph_mount_t*
132 handle->data = cmount;
138 ceph_release(cmount);
142 * Handle the error correctly. Ceph returns -errno.
144 DBG_DEBUG("[CEPH] Error return: %s\n", strerror(-ret));
148 static void cephwrap_disconnect(struct vfs_handle_struct *handle)
153 DBG_ERR("[CEPH] Error, ceph not mounted\n");
157 /* Should we unmount/shutdown? Only if the last disconnect? */
159 DBG_DEBUG("[CEPH] Not shuting down CEPH because still more connections\n");
163 ret = ceph_unmount(cmount);
165 DBG_ERR("[CEPH] failed to unmount: %s\n", strerror(-ret));
168 ret = ceph_release(cmount);
170 DBG_ERR("[CEPH] failed to release: %s\n", strerror(-ret));
173 cmount = NULL; /* Make it safe */
176 /* Disk operations */
178 static uint64_t cephwrap_disk_free(struct vfs_handle_struct *handle,
179 const struct smb_filename *smb_fname,
184 struct statvfs statvfs_buf;
187 if (!(ret = ceph_statfs(handle->data, smb_fname->base_name,
190 * Provide all the correct values.
192 *bsize = statvfs_buf.f_bsize;
193 *dfree = statvfs_buf.f_bavail;
194 *dsize = statvfs_buf.f_blocks;
195 DBG_DEBUG("[CEPH] bsize: %llu, dfree: %llu, dsize: %llu\n",
196 llu(*bsize), llu(*dfree), llu(*dsize));
199 DBG_DEBUG("[CEPH] ceph_statfs returned %d\n", ret);
204 static int cephwrap_get_quota(struct vfs_handle_struct *handle,
205 const struct smb_filename *smb_fname,
206 enum SMB_QUOTA_TYPE qtype,
210 /* libceph: Ceph does not implement this */
212 /* was ifdef HAVE_SYS_QUOTAS */
215 ret = ceph_get_quota(handle->conn->connectpath, qtype, id, qt);
229 static int cephwrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
231 /* libceph: Ceph does not implement this */
233 /* was ifdef HAVE_SYS_QUOTAS */
236 ret = ceph_set_quota(handle->conn->connectpath, qtype, id, qt);
244 WRAP_RETURN(-ENOSYS);
248 static int cephwrap_statvfs(struct vfs_handle_struct *handle,
249 const struct smb_filename *smb_fname,
250 vfs_statvfs_struct *statbuf)
252 struct statvfs statvfs_buf;
255 ret = ceph_statfs(handle->data, smb_fname->base_name, &statvfs_buf);
259 statbuf->OptimalTransferSize = statvfs_buf.f_frsize;
260 statbuf->BlockSize = statvfs_buf.f_bsize;
261 statbuf->TotalBlocks = statvfs_buf.f_blocks;
262 statbuf->BlocksAvail = statvfs_buf.f_bfree;
263 statbuf->UserBlocksAvail = statvfs_buf.f_bavail;
264 statbuf->TotalFileNodes = statvfs_buf.f_files;
265 statbuf->FreeFileNodes = statvfs_buf.f_ffree;
266 statbuf->FsIdentifier = statvfs_buf.f_fsid;
267 DBG_DEBUG("[CEPH] f_bsize: %ld, f_blocks: %ld, f_bfree: %ld, f_bavail: %ld\n",
268 (long int)statvfs_buf.f_bsize, (long int)statvfs_buf.f_blocks,
269 (long int)statvfs_buf.f_bfree, (long int)statvfs_buf.f_bavail);
274 static uint32_t cephwrap_fs_capabilities(struct vfs_handle_struct *handle,
275 enum timestamp_set_resolution *p_ts_res)
277 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
279 #ifdef HAVE_CEPH_STATX
280 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
282 *p_ts_res = TIMESTAMP_SET_MSEC;
288 /* Directory operations */
290 static DIR *cephwrap_opendir(struct vfs_handle_struct *handle,
291 const struct smb_filename *smb_fname,
292 const char *mask, uint32_t attr)
295 struct ceph_dir_result *result;
296 DBG_DEBUG("[CEPH] opendir(%p, %s)\n", handle, smb_fname->base_name);
298 /* Returns NULL if it does not exist or there are problems ? */
299 ret = ceph_opendir(handle->data, smb_fname->base_name, &result);
302 errno = -ret; /* We return result which is NULL in this case */
305 DBG_DEBUG("[CEPH] opendir(...) = %d\n", ret);
306 return (DIR *) result;
309 static DIR *cephwrap_fdopendir(struct vfs_handle_struct *handle,
310 struct files_struct *fsp,
315 struct ceph_dir_result *result;
316 DBG_DEBUG("[CEPH] fdopendir(%p, %p)\n", handle, fsp);
318 ret = ceph_opendir(handle->data, fsp->fsp_name->base_name, &result);
321 errno = -ret; /* We return result which is NULL in this case */
324 DBG_DEBUG("[CEPH] fdopendir(...) = %d\n", ret);
325 return (DIR *) result;
328 static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
330 SMB_STRUCT_STAT *sbuf)
332 struct dirent *result;
334 DBG_DEBUG("[CEPH] readdir(%p, %p)\n", handle, dirp);
335 result = ceph_readdir(handle->data, (struct ceph_dir_result *) dirp);
336 DBG_DEBUG("[CEPH] readdir(...) = %p\n", result);
338 /* Default Posix readdir() does not give us stat info.
339 * Set to invalid to indicate we didn't return this info. */
341 SET_STAT_INVALID(*sbuf);
345 static void cephwrap_seekdir(struct vfs_handle_struct *handle, DIR *dirp, long offset)
347 DBG_DEBUG("[CEPH] seekdir(%p, %p, %ld)\n", handle, dirp, offset);
348 ceph_seekdir(handle->data, (struct ceph_dir_result *) dirp, offset);
351 static long cephwrap_telldir(struct vfs_handle_struct *handle, DIR *dirp)
354 DBG_DEBUG("[CEPH] telldir(%p, %p)\n", handle, dirp);
355 ret = ceph_telldir(handle->data, (struct ceph_dir_result *) dirp);
356 DBG_DEBUG("[CEPH] telldir(...) = %ld\n", ret);
360 static void cephwrap_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
362 DBG_DEBUG("[CEPH] rewinddir(%p, %p)\n", handle, dirp);
363 ceph_rewinddir(handle->data, (struct ceph_dir_result *) dirp);
366 static int cephwrap_mkdir(struct vfs_handle_struct *handle,
367 const struct smb_filename *smb_fname,
371 bool has_dacl = False;
373 const char *path = smb_fname->base_name;
375 DBG_DEBUG("[CEPH] mkdir(%p, %s)\n", handle, path);
377 if (lp_inherit_acls(SNUM(handle->conn))
378 && parent_dirname(talloc_tos(), path, &parent, NULL)
379 && (has_dacl = directory_has_default_acl(handle->conn, parent)))
384 result = ceph_mkdir(handle->data, path, mode);
387 * Note. This order is important
391 } else if (result == 0 && !has_dacl) {
393 * We need to do this as the default behavior of POSIX ACLs
394 * is to set the mask to be the requested group permission
395 * bits, not the group permission bits to be the requested
396 * group permission bits. This is not what we want, as it will
397 * mess up any inherited ACL bits that were set. JRA.
399 int saved_errno = errno; /* We may get ENOSYS */
400 if ((SMB_VFS_CHMOD_ACL(handle->conn, smb_fname, mode) == -1) &&
409 static int cephwrap_rmdir(struct vfs_handle_struct *handle,
410 const struct smb_filename *smb_fname)
414 DBG_DEBUG("[CEPH] rmdir(%p, %s)\n", handle, smb_fname->base_name);
415 result = ceph_rmdir(handle->data, smb_fname->base_name);
416 DBG_DEBUG("[CEPH] rmdir(...) = %d\n", result);
420 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
424 DBG_DEBUG("[CEPH] closedir(%p, %p)\n", handle, dirp);
425 result = ceph_closedir(handle->data, (struct ceph_dir_result *) dirp);
426 DBG_DEBUG("[CEPH] closedir(...) = %d\n", result);
430 /* File operations */
432 static int cephwrap_open(struct vfs_handle_struct *handle,
433 struct smb_filename *smb_fname,
434 files_struct *fsp, int flags, mode_t mode)
436 int result = -ENOENT;
437 DBG_DEBUG("[CEPH] open(%p, %s, %p, %d, %d)\n", handle,
438 smb_fname_str_dbg(smb_fname), fsp, flags, mode);
440 if (smb_fname->stream_name) {
444 result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
446 DBG_DEBUG("[CEPH] open(...) = %d\n", result);
450 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
454 DBG_DEBUG("[CEPH] close(%p, %p)\n", handle, fsp);
455 result = ceph_close(handle->data, fsp->fh->fd);
456 DBG_DEBUG("[CEPH] close(...) = %d\n", result);
461 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
462 size_t n, off_t offset)
466 DBG_DEBUG("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
468 result = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
469 DBG_DEBUG("[CEPH] pread(...) = %llu\n", llu(result));
474 static ssize_t cephwrap_write(struct vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
478 DBG_DEBUG("[CEPH] write(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
480 result = ceph_write(handle->data, fsp->fh->fd, data, n, -1);
482 DBG_DEBUG("[CEPH] write(...) = %llu\n", llu(result));
486 fsp->fh->pos += result;
490 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
491 size_t n, off_t offset)
495 DBG_DEBUG("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
496 result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
497 DBG_DEBUG("[CEPH] pwrite(...) = %llu\n", llu(result));
501 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
505 DBG_DEBUG("[CEPH] cephwrap_lseek\n");
506 /* Cope with 'stat' file opens. */
507 if (fsp->fh->fd != -1) {
508 result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
513 static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
514 off_t offset, size_t n)
517 * We cannot support sendfile because libceph is in user space.
519 DBG_DEBUG("[CEPH] cephwrap_sendfile\n");
524 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
531 * We cannot support recvfile because libceph is in user space.
533 DBG_DEBUG("[CEPH] cephwrap_recvfile\n");
538 static int cephwrap_rename(struct vfs_handle_struct *handle,
539 const struct smb_filename *smb_fname_src,
540 const struct smb_filename *smb_fname_dst)
543 DBG_DEBUG("[CEPH] cephwrap_rename\n");
544 if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
549 result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
554 * Fake up an async ceph fsync by calling the sychronous API.
557 static struct tevent_req *cephwrap_fsync_send(struct vfs_handle_struct *handle,
559 struct tevent_context *ev,
562 struct tevent_req *req = NULL;
563 struct vfs_aio_state *state = NULL;
566 DBG_DEBUG("[CEPH] cephwrap_fsync_send\n");
568 req = tevent_req_create(mem_ctx, &state, struct vfs_aio_state);
573 /* Make sync call. */
574 ret = ceph_fsync(handle->data, fsp->fh->fd, false);
577 /* ceph_fsync returns -errno on error. */
578 tevent_req_error(req, -ret);
579 return tevent_req_post(req, ev);
582 /* Mark it as done. */
583 tevent_req_done(req);
584 /* Return and schedule the completion of the call. */
585 return tevent_req_post(req, ev);
588 static int cephwrap_fsync_recv(struct tevent_req *req,
589 struct vfs_aio_state *vfs_aio_state)
591 struct vfs_aio_state *state =
592 tevent_req_data(req, struct vfs_aio_state);
594 DBG_DEBUG("[CEPH] cephwrap_fsync_recv\n");
596 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
599 *vfs_aio_state = *state;
603 #ifdef HAVE_CEPH_STATX
604 #define SAMBA_STATX_ATTR_MASK (CEPH_STATX_BASIC_STATS|CEPH_STATX_BTIME)
606 static void init_stat_ex_from_ceph_statx(struct stat_ex *dst, const struct ceph_statx *stx)
608 if ((stx->stx_mask & SAMBA_STATX_ATTR_MASK) != SAMBA_STATX_ATTR_MASK)
609 DBG_WARNING("%s: stx->stx_mask is incorrect (wanted %x, got %x)",
610 __func__, SAMBA_STATX_ATTR_MASK, stx->stx_mask);
612 dst->st_ex_dev = stx->stx_dev;
613 dst->st_ex_rdev = stx->stx_rdev;
614 dst->st_ex_ino = stx->stx_ino;
615 dst->st_ex_mode = stx->stx_mode;
616 dst->st_ex_uid = stx->stx_uid;
617 dst->st_ex_gid = stx->stx_gid;
618 dst->st_ex_size = stx->stx_size;
619 dst->st_ex_nlink = stx->stx_nlink;
620 dst->st_ex_atime = stx->stx_atime;
621 dst->st_ex_btime = stx->stx_btime;
622 dst->st_ex_ctime = stx->stx_ctime;
623 dst->st_ex_mtime = stx->stx_mtime;
624 dst->st_ex_calculated_birthtime = false;
625 dst->st_ex_blksize = stx->stx_blksize;
626 dst->st_ex_blocks = stx->stx_blocks;
629 static int cephwrap_stat(struct vfs_handle_struct *handle,
630 struct smb_filename *smb_fname)
633 struct ceph_statx stx;
635 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
637 if (smb_fname->stream_name) {
642 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
643 SAMBA_STATX_ATTR_MASK, 0);
644 DBG_DEBUG("[CEPH] statx(...) = %d\n", result);
648 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
649 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
650 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
651 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
652 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
653 llu(stx.stx_size), llu(stx.stx_blksize),
654 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
655 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
657 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
658 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
662 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
665 struct ceph_statx stx;
667 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
668 result = ceph_fstatx(handle->data, fsp->fh->fd, &stx,
669 SAMBA_STATX_ATTR_MASK, 0);
670 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
674 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
675 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
676 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
677 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
678 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
679 llu(stx.stx_size), llu(stx.stx_blksize),
680 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
681 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
683 init_stat_ex_from_ceph_statx(sbuf, &stx);
684 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
688 static int cephwrap_lstat(struct vfs_handle_struct *handle,
689 struct smb_filename *smb_fname)
692 struct ceph_statx stx;
694 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
696 if (smb_fname->stream_name) {
701 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
702 SAMBA_STATX_ATTR_MASK, AT_SYMLINK_NOFOLLOW);
703 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
707 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
711 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
712 const struct smb_filename *smb_fname,
713 struct smb_file_time *ft)
715 struct ceph_statx stx = { 0 };
719 if (!null_timespec(ft->atime)) {
720 stx.stx_atime = ft->atime;
721 mask |= CEPH_SETATTR_ATIME;
723 if (!null_timespec(ft->mtime)) {
724 stx.stx_mtime = ft->mtime;
725 mask |= CEPH_SETATTR_MTIME;
727 if (!null_timespec(ft->create_time)) {
728 stx.stx_btime = ft->create_time;
729 mask |= CEPH_SETATTR_BTIME;
736 result = ceph_setattrx(handle->data, smb_fname->base_name, &stx, mask, 0);
737 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
738 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
739 ft->create_time.tv_sec, result);
743 #else /* HAVE_CEPH_STATX */
745 static int cephwrap_stat(struct vfs_handle_struct *handle,
746 struct smb_filename *smb_fname)
751 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
753 if (smb_fname->stream_name) {
758 result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
759 DBG_DEBUG("[CEPH] stat(...) = %d\n", result);
763 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
764 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
765 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
766 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
767 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
768 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
770 init_stat_ex_from_stat(
771 &smb_fname->st, &stbuf,
772 lp_fake_directory_create_times(SNUM(handle->conn)));
773 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
777 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
782 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
783 result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
784 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
788 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
789 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
790 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
791 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
792 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
793 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
796 init_stat_ex_from_stat(
798 lp_fake_directory_create_times(SNUM(handle->conn)));
799 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
803 static int cephwrap_lstat(struct vfs_handle_struct *handle,
804 struct smb_filename *smb_fname)
809 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
811 if (smb_fname->stream_name) {
816 result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
817 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
821 init_stat_ex_from_stat(
822 &smb_fname->st, &stbuf,
823 lp_fake_directory_create_times(SNUM(handle->conn)));
827 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
828 const struct smb_filename *smb_fname,
829 struct smb_file_time *ft)
834 if (null_timespec(ft->atime)) {
835 buf.actime = smb_fname->st.st_ex_atime.tv_sec;
837 buf.actime = ft->atime.tv_sec;
839 if (null_timespec(ft->mtime)) {
840 buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
842 buf.modtime = ft->mtime.tv_sec;
844 if (!null_timespec(ft->create_time)) {
845 set_create_timespec_ea(handle->conn, smb_fname,
848 if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
849 buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
853 result = ceph_utime(handle->data, smb_fname->base_name, &buf);
854 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
855 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
856 ft->create_time.tv_sec, result);
859 #endif /* HAVE_CEPH_STATX */
861 static int cephwrap_unlink(struct vfs_handle_struct *handle,
862 const struct smb_filename *smb_fname)
866 DBG_DEBUG("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
867 if (smb_fname->stream_name) {
871 result = ceph_unlink(handle->data, smb_fname->base_name);
872 DBG_DEBUG("[CEPH] unlink(...) = %d\n", result);
876 static int cephwrap_chmod(struct vfs_handle_struct *handle,
877 const struct smb_filename *smb_fname,
882 DBG_DEBUG("[CEPH] chmod(%p, %s, %d)\n", handle, smb_fname->base_name, mode);
885 * We need to do this due to the fact that the default POSIX ACL
886 * chmod modifies the ACL *mask* for the group owner, not the
887 * group owner bits directly. JRA.
892 int saved_errno = errno; /* We might get ENOSYS */
893 result = SMB_VFS_CHMOD_ACL(handle->conn,
899 /* Error - return the old errno. */
903 result = ceph_chmod(handle->data, smb_fname->base_name, mode);
904 DBG_DEBUG("[CEPH] chmod(...) = %d\n", result);
908 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
912 DBG_DEBUG("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode);
915 * We need to do this due to the fact that the default POSIX ACL
916 * chmod modifies the ACL *mask* for the group owner, not the
917 * group owner bits directly. JRA.
921 int saved_errno = errno; /* We might get ENOSYS */
922 if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
925 /* Error - return the old errno. */
929 #if defined(HAVE_FCHMOD)
930 result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
931 DBG_DEBUG("[CEPH] fchmod(...) = %d\n", result);
939 static int cephwrap_chown(struct vfs_handle_struct *handle,
940 const struct smb_filename *smb_fname,
945 DBG_DEBUG("[CEPH] chown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
946 result = ceph_chown(handle->data, smb_fname->base_name, uid, gid);
947 DBG_DEBUG("[CEPH] chown(...) = %d\n", result);
951 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
956 DBG_DEBUG("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid);
957 result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
958 DBG_DEBUG("[CEPH] fchown(...) = %d\n", result);
967 static int cephwrap_lchown(struct vfs_handle_struct *handle,
968 const struct smb_filename *smb_fname,
973 DBG_DEBUG("[CEPH] lchown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
974 result = ceph_lchown(handle->data, smb_fname->base_name, uid, gid);
975 DBG_DEBUG("[CEPH] lchown(...) = %d\n", result);
979 static int cephwrap_chdir(struct vfs_handle_struct *handle,
980 const struct smb_filename *smb_fname)
983 DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, smb_fname->base_name);
984 result = ceph_chdir(handle->data, smb_fname->base_name);
985 DBG_DEBUG("[CEPH] chdir(...) = %d\n", result);
989 static struct smb_filename *cephwrap_getwd(struct vfs_handle_struct *handle,
992 const char *cwd = ceph_getcwd(handle->data);
993 DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd);
994 return synthetic_smb_fname(ctx,
1001 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1003 off_t space_to_write;
1004 uint64_t space_avail;
1005 uint64_t bsize,dfree,dsize;
1008 SMB_STRUCT_STAT *pst;
1010 status = vfs_stat_fsp(fsp);
1011 if (!NT_STATUS_IS_OK(status)) {
1014 pst = &fsp->fsp_name->st;
1017 if (S_ISFIFO(pst->st_ex_mode))
1021 if (pst->st_ex_size == len)
1024 /* Shrink - just ftruncate. */
1025 if (pst->st_ex_size > len)
1026 return ftruncate(fsp->fh->fd, len);
1028 space_to_write = len - pst->st_ex_size;
1030 /* for allocation try fallocate first. This can fail on some
1031 platforms e.g. when the filesystem doesn't support it and no
1032 emulation is being done by the libc (like on AIX with JFS1). In that
1033 case we do our own emulation. fallocate implementations can
1034 return ENOTSUP or EINVAL in cases like that. */
1035 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
1036 if (ret == -1 && errno == ENOSPC) {
1042 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
1043 "error %d. Falling back to slow manual allocation\n", errno));
1045 /* available disk space is enough or not? */
1047 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
1048 /* space_avail is 1k blocks */
1049 if (space_avail == (uint64_t)-1 ||
1050 ((uint64_t)space_to_write/1024 > space_avail) ) {
1055 /* Write out the real space on disk. */
1056 return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
1059 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1066 DBG_DEBUG("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len));
1068 if (lp_strict_allocate(SNUM(fsp->conn))) {
1069 result = strict_allocate_ftruncate(handle, fsp, len);
1073 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
1074 sys_ftruncate if the system supports it. Then I discovered that
1075 you can have some filesystems that support ftruncate
1076 expansion and some that don't! On Linux fat can't do
1077 ftruncate extend but ext2 can. */
1079 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1083 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
1084 extend a file with ftruncate. Provide alternate implementation
1086 currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
1087 if (currpos == -1) {
1091 /* Do an fstat to see if the file is longer than the requested
1092 size in which case the ftruncate above should have
1093 succeeded or shorter, in which case seek to len - 1 and
1094 write 1 byte of zero */
1095 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
1100 if (S_ISFIFO(st.st_ex_mode)) {
1106 if (st.st_ex_size == len) {
1111 if (st.st_ex_size > len) {
1112 /* the sys_ftruncate should have worked */
1116 if (SMB_VFS_LSEEK(fsp, len-1, SEEK_SET) != len -1)
1119 if (SMB_VFS_WRITE(fsp, &c, 1)!=1)
1122 /* Seek to where we were */
1123 if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
1132 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
1134 DBG_DEBUG("[CEPH] lock\n");
1138 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
1139 uint32_t share_mode, uint32_t access_mask)
1141 DBG_DEBUG("[CEPH] kernel_flock\n");
1143 * We must return zero here and pretend all is good.
1144 * One day we might have this in CEPH.
1149 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
1151 DBG_DEBUG("[CEPH] getlock returning false and errno=0\n");
1158 * We cannot let this fall through to the default, because the file might only
1159 * be accessible from libceph (which is a user-space client) but the fd might
1160 * be for some file the kernel knows about.
1162 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
1167 DBG_DEBUG("[CEPH] linux_setlease\n");
1172 static int cephwrap_symlink(struct vfs_handle_struct *handle,
1173 const char *link_target,
1174 const struct smb_filename *new_smb_fname)
1177 DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle,
1179 new_smb_fname->base_name);
1180 result = ceph_symlink(handle->data,
1182 new_smb_fname->base_name);
1183 DBG_DEBUG("[CEPH] symlink(...) = %d\n", result);
1184 WRAP_RETURN(result);
1187 static int cephwrap_readlink(struct vfs_handle_struct *handle,
1188 const struct smb_filename *smb_fname,
1193 DBG_DEBUG("[CEPH] readlink(%p, %s, %p, %llu)\n", handle,
1194 smb_fname->base_name, buf, llu(bufsiz));
1195 result = ceph_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1196 DBG_DEBUG("[CEPH] readlink(...) = %d\n", result);
1197 WRAP_RETURN(result);
1200 static int cephwrap_link(struct vfs_handle_struct *handle,
1201 const struct smb_filename *old_smb_fname,
1202 const struct smb_filename *new_smb_fname)
1205 DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle,
1206 old_smb_fname->base_name,
1207 new_smb_fname->base_name);
1208 result = ceph_link(handle->data,
1209 old_smb_fname->base_name,
1210 new_smb_fname->base_name);
1211 DBG_DEBUG("[CEPH] link(...) = %d\n", result);
1212 WRAP_RETURN(result);
1215 static int cephwrap_mknod(struct vfs_handle_struct *handle,
1216 const struct smb_filename *smb_fname,
1221 DBG_DEBUG("[CEPH] mknod(%p, %s)\n", handle, smb_fname->base_name);
1222 result = ceph_mknod(handle->data, smb_fname->base_name, mode, dev);
1223 DBG_DEBUG("[CEPH] mknod(...) = %d\n", result);
1224 WRAP_RETURN(result);
1228 * This is a simple version of real-path ... a better version is needed to
1229 * ask libceph about symbolic links.
1231 static struct smb_filename *cephwrap_realpath(struct vfs_handle_struct *handle,
1233 const struct smb_filename *smb_fname)
1236 const char *path = smb_fname->base_name;
1237 size_t len = strlen(path);
1238 struct smb_filename *result_fname = NULL;
1240 result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1241 if (len && (path[0] == '/')) {
1242 int r = asprintf(&result, "%s", path);
1243 if (r < 0) return NULL;
1244 } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1246 int r = asprintf(&result, "%s",
1247 handle->conn->connectpath);
1248 if (r < 0) return NULL;
1250 int r = asprintf(&result, "%s/%s",
1251 handle->conn->connectpath, &path[2]);
1252 if (r < 0) return NULL;
1255 int r = asprintf(&result, "%s/%s",
1256 handle->conn->connectpath, path);
1257 if (r < 0) return NULL;
1259 DBG_DEBUG("[CEPH] realpath(%p, %s) = %s\n", handle, path, result);
1260 result_fname = synthetic_smb_fname(ctx,
1266 return result_fname;
1269 static int cephwrap_chflags(struct vfs_handle_struct *handle,
1270 const struct smb_filename *smb_fname,
1277 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1280 TALLOC_CTX *mem_ctx,
1284 * Don't fall back to get_real_filename so callers can differentiate
1285 * between a full directory scan and an actual case-insensitive stat.
1291 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1292 const struct smb_filename *smb_fname)
1294 return handle->conn->connectpath;
1297 /****************************************************************
1298 Extended attribute operations.
1299 *****************************************************************/
1301 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,
1302 const struct smb_filename *smb_fname,
1308 DBG_DEBUG("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle,
1309 smb_fname->base_name, name, value, llu(size));
1310 ret = ceph_getxattr(handle->data,
1311 smb_fname->base_name, name, value, size);
1312 DBG_DEBUG("[CEPH] getxattr(...) = %d\n", ret);
1316 return (ssize_t)ret;
1320 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1323 DBG_DEBUG("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size));
1324 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1325 ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1327 ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1329 DBG_DEBUG("[CEPH] fgetxattr(...) = %d\n", ret);
1333 return (ssize_t)ret;
1337 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle,
1338 const struct smb_filename *smb_fname,
1343 DBG_DEBUG("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle,
1344 smb_fname->base_name, list, llu(size));
1345 ret = ceph_listxattr(handle->data, smb_fname->base_name, list, size);
1346 DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
1350 return (ssize_t)ret;
1354 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1357 DBG_DEBUG("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size));
1358 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1359 ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1361 ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1363 DBG_DEBUG("[CEPH] flistxattr(...) = %d\n", ret);
1367 return (ssize_t)ret;
1371 static int cephwrap_removexattr(struct vfs_handle_struct *handle,
1372 const struct smb_filename *smb_fname,
1376 DBG_DEBUG("[CEPH] removexattr(%p, %s, %s)\n", handle,
1377 smb_fname->base_name, name);
1378 ret = ceph_removexattr(handle->data, smb_fname->base_name, name);
1379 DBG_DEBUG("[CEPH] removexattr(...) = %d\n", ret);
1383 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1386 DBG_DEBUG("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name);
1387 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1388 ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1390 ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1392 DBG_DEBUG("[CEPH] fremovexattr(...) = %d\n", ret);
1396 static int cephwrap_setxattr(struct vfs_handle_struct *handle,
1397 const struct smb_filename *smb_fname,
1404 DBG_DEBUG("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle,
1405 smb_fname->base_name, name, value, llu(size), flags);
1406 ret = ceph_setxattr(handle->data, smb_fname->base_name,
1407 name, value, size, flags);
1408 DBG_DEBUG("[CEPH] setxattr(...) = %d\n", ret);
1412 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1415 DBG_DEBUG("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags);
1416 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1417 ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1418 name, value, size, flags);
1420 ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1422 DBG_DEBUG("[CEPH] fsetxattr(...) = %d\n", ret);
1426 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1430 * We do not support AIO yet.
1433 DBG_DEBUG("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp);
1438 static struct vfs_fn_pointers ceph_fns = {
1439 /* Disk operations */
1441 .connect_fn = cephwrap_connect,
1442 .disconnect_fn = cephwrap_disconnect,
1443 .disk_free_fn = cephwrap_disk_free,
1444 .get_quota_fn = cephwrap_get_quota,
1445 .set_quota_fn = cephwrap_set_quota,
1446 .statvfs_fn = cephwrap_statvfs,
1447 .fs_capabilities_fn = cephwrap_fs_capabilities,
1449 /* Directory operations */
1451 .opendir_fn = cephwrap_opendir,
1452 .fdopendir_fn = cephwrap_fdopendir,
1453 .readdir_fn = cephwrap_readdir,
1454 .seekdir_fn = cephwrap_seekdir,
1455 .telldir_fn = cephwrap_telldir,
1456 .rewind_dir_fn = cephwrap_rewinddir,
1457 .mkdir_fn = cephwrap_mkdir,
1458 .rmdir_fn = cephwrap_rmdir,
1459 .closedir_fn = cephwrap_closedir,
1461 /* File operations */
1463 .open_fn = cephwrap_open,
1464 .close_fn = cephwrap_close,
1465 .pread_fn = cephwrap_pread,
1466 .write_fn = cephwrap_write,
1467 .pwrite_fn = cephwrap_pwrite,
1468 .lseek_fn = cephwrap_lseek,
1469 .sendfile_fn = cephwrap_sendfile,
1470 .recvfile_fn = cephwrap_recvfile,
1471 .rename_fn = cephwrap_rename,
1472 .fsync_send_fn = cephwrap_fsync_send,
1473 .fsync_recv_fn = cephwrap_fsync_recv,
1474 .stat_fn = cephwrap_stat,
1475 .fstat_fn = cephwrap_fstat,
1476 .lstat_fn = cephwrap_lstat,
1477 .unlink_fn = cephwrap_unlink,
1478 .chmod_fn = cephwrap_chmod,
1479 .fchmod_fn = cephwrap_fchmod,
1480 .chown_fn = cephwrap_chown,
1481 .fchown_fn = cephwrap_fchown,
1482 .lchown_fn = cephwrap_lchown,
1483 .chdir_fn = cephwrap_chdir,
1484 .getwd_fn = cephwrap_getwd,
1485 .ntimes_fn = cephwrap_ntimes,
1486 .ftruncate_fn = cephwrap_ftruncate,
1487 .lock_fn = cephwrap_lock,
1488 .kernel_flock_fn = cephwrap_kernel_flock,
1489 .linux_setlease_fn = cephwrap_linux_setlease,
1490 .getlock_fn = cephwrap_getlock,
1491 .symlink_fn = cephwrap_symlink,
1492 .readlink_fn = cephwrap_readlink,
1493 .link_fn = cephwrap_link,
1494 .mknod_fn = cephwrap_mknod,
1495 .realpath_fn = cephwrap_realpath,
1496 .chflags_fn = cephwrap_chflags,
1497 .get_real_filename_fn = cephwrap_get_real_filename,
1498 .connectpath_fn = cephwrap_connectpath,
1500 /* EA operations. */
1501 .getxattr_fn = cephwrap_getxattr,
1502 .fgetxattr_fn = cephwrap_fgetxattr,
1503 .listxattr_fn = cephwrap_listxattr,
1504 .flistxattr_fn = cephwrap_flistxattr,
1505 .removexattr_fn = cephwrap_removexattr,
1506 .fremovexattr_fn = cephwrap_fremovexattr,
1507 .setxattr_fn = cephwrap_setxattr,
1508 .fsetxattr_fn = cephwrap_fsetxattr,
1510 /* Posix ACL Operations */
1511 .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
1512 .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
1513 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1514 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1515 .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
1516 .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
1517 .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
1519 /* aio operations */
1520 .aio_force_fn = cephwrap_aio_force,
1524 NTSTATUS vfs_ceph_init(TALLOC_CTX *ctx)
1526 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,