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_read(struct vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n)
465 DBG_DEBUG("[CEPH] read(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
467 /* Using -1 for the offset means read/write rather than pread/pwrite */
468 result = ceph_read(handle->data, fsp->fh->fd, data, n, -1);
469 DBG_DEBUG("[CEPH] read(...) = %llu\n", llu(result));
473 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
474 size_t n, off_t offset)
478 DBG_DEBUG("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
480 result = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
481 DBG_DEBUG("[CEPH] pread(...) = %llu\n", llu(result));
486 static ssize_t cephwrap_write(struct vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
490 DBG_DEBUG("[CEPH] write(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
492 result = ceph_write(handle->data, fsp->fh->fd, data, n, -1);
494 DBG_DEBUG("[CEPH] write(...) = %llu\n", llu(result));
498 fsp->fh->pos += result;
502 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
503 size_t n, off_t offset)
507 DBG_DEBUG("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
508 result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
509 DBG_DEBUG("[CEPH] pwrite(...) = %llu\n", llu(result));
513 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
517 DBG_DEBUG("[CEPH] cephwrap_lseek\n");
518 /* Cope with 'stat' file opens. */
519 if (fsp->fh->fd != -1) {
520 result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
525 static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
526 off_t offset, size_t n)
529 * We cannot support sendfile because libceph is in user space.
531 DBG_DEBUG("[CEPH] cephwrap_sendfile\n");
536 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
543 * We cannot support recvfile because libceph is in user space.
545 DBG_DEBUG("[CEPH] cephwrap_recvfile\n");
550 static int cephwrap_rename(struct vfs_handle_struct *handle,
551 const struct smb_filename *smb_fname_src,
552 const struct smb_filename *smb_fname_dst)
555 DBG_DEBUG("[CEPH] cephwrap_rename\n");
556 if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
561 result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
565 static int cephwrap_fsync(struct vfs_handle_struct *handle, files_struct *fsp)
568 DBG_DEBUG("[CEPH] cephwrap_fsync\n");
569 result = ceph_fsync(handle->data, fsp->fh->fd, false);
574 * Fake up an async ceph fsync by calling the sychronous API.
577 static struct tevent_req *cephwrap_fsync_send(struct vfs_handle_struct *handle,
579 struct tevent_context *ev,
582 struct tevent_req *req = NULL;
583 struct vfs_aio_state *state = NULL;
586 DBG_DEBUG("[CEPH] cephwrap_fsync_send\n");
588 req = tevent_req_create(mem_ctx, &state, struct vfs_aio_state);
593 /* Make sync call. */
594 ret = ceph_fsync(handle->data, fsp->fh->fd, false);
597 /* ceph_fsync returns -errno on error. */
598 tevent_req_error(req, -ret);
599 return tevent_req_post(req, ev);
602 /* Mark it as done. */
603 tevent_req_done(req);
604 /* Return and schedule the completion of the call. */
605 return tevent_req_post(req, ev);
608 static int cephwrap_fsync_recv(struct tevent_req *req,
609 struct vfs_aio_state *vfs_aio_state)
611 struct vfs_aio_state *state =
612 tevent_req_data(req, struct vfs_aio_state);
614 DBG_DEBUG("[CEPH] cephwrap_fsync_recv\n");
616 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
619 *vfs_aio_state = *state;
623 #ifdef HAVE_CEPH_STATX
624 #define SAMBA_STATX_ATTR_MASK (CEPH_STATX_BASIC_STATS|CEPH_STATX_BTIME)
626 static void init_stat_ex_from_ceph_statx(struct stat_ex *dst, const struct ceph_statx *stx)
628 if ((stx->stx_mask & SAMBA_STATX_ATTR_MASK) != SAMBA_STATX_ATTR_MASK)
629 DBG_WARNING("%s: stx->stx_mask is incorrect (wanted %x, got %x)",
630 __func__, SAMBA_STATX_ATTR_MASK, stx->stx_mask);
632 dst->st_ex_dev = stx->stx_dev;
633 dst->st_ex_rdev = stx->stx_rdev;
634 dst->st_ex_ino = stx->stx_ino;
635 dst->st_ex_mode = stx->stx_mode;
636 dst->st_ex_uid = stx->stx_uid;
637 dst->st_ex_gid = stx->stx_gid;
638 dst->st_ex_size = stx->stx_size;
639 dst->st_ex_nlink = stx->stx_nlink;
640 dst->st_ex_atime = stx->stx_atime;
641 dst->st_ex_btime = stx->stx_btime;
642 dst->st_ex_ctime = stx->stx_ctime;
643 dst->st_ex_mtime = stx->stx_mtime;
644 dst->st_ex_calculated_birthtime = false;
645 dst->st_ex_blksize = stx->stx_blksize;
646 dst->st_ex_blocks = stx->stx_blocks;
649 static int cephwrap_stat(struct vfs_handle_struct *handle,
650 struct smb_filename *smb_fname)
653 struct ceph_statx stx;
655 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
657 if (smb_fname->stream_name) {
662 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
663 SAMBA_STATX_ATTR_MASK, 0);
664 DBG_DEBUG("[CEPH] statx(...) = %d\n", result);
668 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
669 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
670 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
671 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
672 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
673 llu(stx.stx_size), llu(stx.stx_blksize),
674 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
675 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
677 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
678 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
682 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
685 struct ceph_statx stx;
687 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
688 result = ceph_fstatx(handle->data, fsp->fh->fd, &stx,
689 SAMBA_STATX_ATTR_MASK, 0);
690 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
694 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
695 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
696 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
697 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
698 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
699 llu(stx.stx_size), llu(stx.stx_blksize),
700 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
701 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
703 init_stat_ex_from_ceph_statx(sbuf, &stx);
704 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
708 static int cephwrap_lstat(struct vfs_handle_struct *handle,
709 struct smb_filename *smb_fname)
712 struct ceph_statx stx;
714 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
716 if (smb_fname->stream_name) {
721 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
722 SAMBA_STATX_ATTR_MASK, AT_SYMLINK_NOFOLLOW);
723 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
727 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
731 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
732 const struct smb_filename *smb_fname,
733 struct smb_file_time *ft)
735 struct ceph_statx stx = { 0 };
739 if (!null_timespec(ft->atime)) {
740 stx.stx_atime = ft->atime;
741 mask |= CEPH_SETATTR_ATIME;
743 if (!null_timespec(ft->mtime)) {
744 stx.stx_mtime = ft->mtime;
745 mask |= CEPH_SETATTR_MTIME;
747 if (!null_timespec(ft->create_time)) {
748 stx.stx_btime = ft->create_time;
749 mask |= CEPH_SETATTR_BTIME;
756 result = ceph_setattrx(handle->data, smb_fname->base_name, &stx, mask, 0);
757 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
758 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
759 ft->create_time.tv_sec, result);
763 #else /* HAVE_CEPH_STATX */
765 static int cephwrap_stat(struct vfs_handle_struct *handle,
766 struct smb_filename *smb_fname)
771 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
773 if (smb_fname->stream_name) {
778 result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
779 DBG_DEBUG("[CEPH] stat(...) = %d\n", result);
783 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
784 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
785 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
786 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
787 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
788 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
790 init_stat_ex_from_stat(
791 &smb_fname->st, &stbuf,
792 lp_fake_directory_create_times(SNUM(handle->conn)));
793 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
797 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
802 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
803 result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
804 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
808 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
809 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
810 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
811 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
812 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
813 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
816 init_stat_ex_from_stat(
818 lp_fake_directory_create_times(SNUM(handle->conn)));
819 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
823 static int cephwrap_lstat(struct vfs_handle_struct *handle,
824 struct smb_filename *smb_fname)
829 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
831 if (smb_fname->stream_name) {
836 result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
837 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
841 init_stat_ex_from_stat(
842 &smb_fname->st, &stbuf,
843 lp_fake_directory_create_times(SNUM(handle->conn)));
847 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
848 const struct smb_filename *smb_fname,
849 struct smb_file_time *ft)
854 if (null_timespec(ft->atime)) {
855 buf.actime = smb_fname->st.st_ex_atime.tv_sec;
857 buf.actime = ft->atime.tv_sec;
859 if (null_timespec(ft->mtime)) {
860 buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
862 buf.modtime = ft->mtime.tv_sec;
864 if (!null_timespec(ft->create_time)) {
865 set_create_timespec_ea(handle->conn, smb_fname,
868 if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
869 buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
873 result = ceph_utime(handle->data, smb_fname->base_name, &buf);
874 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
875 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
876 ft->create_time.tv_sec, result);
879 #endif /* HAVE_CEPH_STATX */
881 static int cephwrap_unlink(struct vfs_handle_struct *handle,
882 const struct smb_filename *smb_fname)
886 DBG_DEBUG("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
887 if (smb_fname->stream_name) {
891 result = ceph_unlink(handle->data, smb_fname->base_name);
892 DBG_DEBUG("[CEPH] unlink(...) = %d\n", result);
896 static int cephwrap_chmod(struct vfs_handle_struct *handle,
897 const struct smb_filename *smb_fname,
902 DBG_DEBUG("[CEPH] chmod(%p, %s, %d)\n", handle, smb_fname->base_name, mode);
905 * We need to do this due to the fact that the default POSIX ACL
906 * chmod modifies the ACL *mask* for the group owner, not the
907 * group owner bits directly. JRA.
912 int saved_errno = errno; /* We might get ENOSYS */
913 result = SMB_VFS_CHMOD_ACL(handle->conn,
919 /* Error - return the old errno. */
923 result = ceph_chmod(handle->data, smb_fname->base_name, mode);
924 DBG_DEBUG("[CEPH] chmod(...) = %d\n", result);
928 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
932 DBG_DEBUG("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode);
935 * We need to do this due to the fact that the default POSIX ACL
936 * chmod modifies the ACL *mask* for the group owner, not the
937 * group owner bits directly. JRA.
941 int saved_errno = errno; /* We might get ENOSYS */
942 if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
945 /* Error - return the old errno. */
949 #if defined(HAVE_FCHMOD)
950 result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
951 DBG_DEBUG("[CEPH] fchmod(...) = %d\n", result);
959 static int cephwrap_chown(struct vfs_handle_struct *handle,
960 const struct smb_filename *smb_fname,
965 DBG_DEBUG("[CEPH] chown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
966 result = ceph_chown(handle->data, smb_fname->base_name, uid, gid);
967 DBG_DEBUG("[CEPH] chown(...) = %d\n", result);
971 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
976 DBG_DEBUG("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid);
977 result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
978 DBG_DEBUG("[CEPH] fchown(...) = %d\n", result);
987 static int cephwrap_lchown(struct vfs_handle_struct *handle,
988 const struct smb_filename *smb_fname,
993 DBG_DEBUG("[CEPH] lchown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
994 result = ceph_lchown(handle->data, smb_fname->base_name, uid, gid);
995 DBG_DEBUG("[CEPH] lchown(...) = %d\n", result);
999 static int cephwrap_chdir(struct vfs_handle_struct *handle,
1000 const struct smb_filename *smb_fname)
1003 DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, smb_fname->base_name);
1004 result = ceph_chdir(handle->data, smb_fname->base_name);
1005 DBG_DEBUG("[CEPH] chdir(...) = %d\n", result);
1006 WRAP_RETURN(result);
1009 static struct smb_filename *cephwrap_getwd(struct vfs_handle_struct *handle,
1012 const char *cwd = ceph_getcwd(handle->data);
1013 DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd);
1014 return synthetic_smb_fname(ctx,
1021 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1023 off_t space_to_write;
1024 uint64_t space_avail;
1025 uint64_t bsize,dfree,dsize;
1028 SMB_STRUCT_STAT *pst;
1030 status = vfs_stat_fsp(fsp);
1031 if (!NT_STATUS_IS_OK(status)) {
1034 pst = &fsp->fsp_name->st;
1037 if (S_ISFIFO(pst->st_ex_mode))
1041 if (pst->st_ex_size == len)
1044 /* Shrink - just ftruncate. */
1045 if (pst->st_ex_size > len)
1046 return ftruncate(fsp->fh->fd, len);
1048 space_to_write = len - pst->st_ex_size;
1050 /* for allocation try fallocate first. This can fail on some
1051 platforms e.g. when the filesystem doesn't support it and no
1052 emulation is being done by the libc (like on AIX with JFS1). In that
1053 case we do our own emulation. fallocate implementations can
1054 return ENOTSUP or EINVAL in cases like that. */
1055 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
1056 if (ret == -1 && errno == ENOSPC) {
1062 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
1063 "error %d. Falling back to slow manual allocation\n", errno));
1065 /* available disk space is enough or not? */
1067 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
1068 /* space_avail is 1k blocks */
1069 if (space_avail == (uint64_t)-1 ||
1070 ((uint64_t)space_to_write/1024 > space_avail) ) {
1075 /* Write out the real space on disk. */
1076 return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
1079 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1086 DBG_DEBUG("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len));
1088 if (lp_strict_allocate(SNUM(fsp->conn))) {
1089 result = strict_allocate_ftruncate(handle, fsp, len);
1093 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
1094 sys_ftruncate if the system supports it. Then I discovered that
1095 you can have some filesystems that support ftruncate
1096 expansion and some that don't! On Linux fat can't do
1097 ftruncate extend but ext2 can. */
1099 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1103 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
1104 extend a file with ftruncate. Provide alternate implementation
1106 currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
1107 if (currpos == -1) {
1111 /* Do an fstat to see if the file is longer than the requested
1112 size in which case the ftruncate above should have
1113 succeeded or shorter, in which case seek to len - 1 and
1114 write 1 byte of zero */
1115 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
1120 if (S_ISFIFO(st.st_ex_mode)) {
1126 if (st.st_ex_size == len) {
1131 if (st.st_ex_size > len) {
1132 /* the sys_ftruncate should have worked */
1136 if (SMB_VFS_LSEEK(fsp, len-1, SEEK_SET) != len -1)
1139 if (SMB_VFS_WRITE(fsp, &c, 1)!=1)
1142 /* Seek to where we were */
1143 if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
1152 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
1154 DBG_DEBUG("[CEPH] lock\n");
1158 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
1159 uint32_t share_mode, uint32_t access_mask)
1161 DBG_DEBUG("[CEPH] kernel_flock\n");
1163 * We must return zero here and pretend all is good.
1164 * One day we might have this in CEPH.
1169 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
1171 DBG_DEBUG("[CEPH] getlock returning false and errno=0\n");
1178 * We cannot let this fall through to the default, because the file might only
1179 * be accessible from libceph (which is a user-space client) but the fd might
1180 * be for some file the kernel knows about.
1182 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
1187 DBG_DEBUG("[CEPH] linux_setlease\n");
1192 static int cephwrap_symlink(struct vfs_handle_struct *handle,
1193 const char *link_target,
1194 const struct smb_filename *new_smb_fname)
1197 DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle,
1199 new_smb_fname->base_name);
1200 result = ceph_symlink(handle->data,
1202 new_smb_fname->base_name);
1203 DBG_DEBUG("[CEPH] symlink(...) = %d\n", result);
1204 WRAP_RETURN(result);
1207 static int cephwrap_readlink(struct vfs_handle_struct *handle,
1208 const struct smb_filename *smb_fname,
1213 DBG_DEBUG("[CEPH] readlink(%p, %s, %p, %llu)\n", handle,
1214 smb_fname->base_name, buf, llu(bufsiz));
1215 result = ceph_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1216 DBG_DEBUG("[CEPH] readlink(...) = %d\n", result);
1217 WRAP_RETURN(result);
1220 static int cephwrap_link(struct vfs_handle_struct *handle,
1221 const struct smb_filename *old_smb_fname,
1222 const struct smb_filename *new_smb_fname)
1225 DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle,
1226 old_smb_fname->base_name,
1227 new_smb_fname->base_name);
1228 result = ceph_link(handle->data,
1229 old_smb_fname->base_name,
1230 new_smb_fname->base_name);
1231 DBG_DEBUG("[CEPH] link(...) = %d\n", result);
1232 WRAP_RETURN(result);
1235 static int cephwrap_mknod(struct vfs_handle_struct *handle,
1236 const struct smb_filename *smb_fname,
1241 DBG_DEBUG("[CEPH] mknod(%p, %s)\n", handle, smb_fname->base_name);
1242 result = ceph_mknod(handle->data, smb_fname->base_name, mode, dev);
1243 DBG_DEBUG("[CEPH] mknod(...) = %d\n", result);
1244 WRAP_RETURN(result);
1248 * This is a simple version of real-path ... a better version is needed to
1249 * ask libceph about symbolic links.
1251 static struct smb_filename *cephwrap_realpath(struct vfs_handle_struct *handle,
1253 const struct smb_filename *smb_fname)
1256 const char *path = smb_fname->base_name;
1257 size_t len = strlen(path);
1258 struct smb_filename *result_fname = NULL;
1260 result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1261 if (len && (path[0] == '/')) {
1262 int r = asprintf(&result, "%s", path);
1263 if (r < 0) return NULL;
1264 } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1266 int r = asprintf(&result, "%s",
1267 handle->conn->connectpath);
1268 if (r < 0) return NULL;
1270 int r = asprintf(&result, "%s/%s",
1271 handle->conn->connectpath, &path[2]);
1272 if (r < 0) return NULL;
1275 int r = asprintf(&result, "%s/%s",
1276 handle->conn->connectpath, path);
1277 if (r < 0) return NULL;
1279 DBG_DEBUG("[CEPH] realpath(%p, %s) = %s\n", handle, path, result);
1280 result_fname = synthetic_smb_fname(ctx,
1286 return result_fname;
1289 static int cephwrap_chflags(struct vfs_handle_struct *handle,
1290 const struct smb_filename *smb_fname,
1297 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1300 TALLOC_CTX *mem_ctx,
1304 * Don't fall back to get_real_filename so callers can differentiate
1305 * between a full directory scan and an actual case-insensitive stat.
1311 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1312 const struct smb_filename *smb_fname)
1314 return handle->conn->connectpath;
1317 /****************************************************************
1318 Extended attribute operations.
1319 *****************************************************************/
1321 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,
1322 const struct smb_filename *smb_fname,
1328 DBG_DEBUG("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle,
1329 smb_fname->base_name, name, value, llu(size));
1330 ret = ceph_getxattr(handle->data,
1331 smb_fname->base_name, name, value, size);
1332 DBG_DEBUG("[CEPH] getxattr(...) = %d\n", ret);
1336 return (ssize_t)ret;
1340 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1343 DBG_DEBUG("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size));
1344 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1345 ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1347 ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1349 DBG_DEBUG("[CEPH] fgetxattr(...) = %d\n", ret);
1353 return (ssize_t)ret;
1357 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle,
1358 const struct smb_filename *smb_fname,
1363 DBG_DEBUG("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle,
1364 smb_fname->base_name, list, llu(size));
1365 ret = ceph_listxattr(handle->data, smb_fname->base_name, list, size);
1366 DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
1370 return (ssize_t)ret;
1374 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1377 DBG_DEBUG("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size));
1378 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1379 ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1381 ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1383 DBG_DEBUG("[CEPH] flistxattr(...) = %d\n", ret);
1387 return (ssize_t)ret;
1391 static int cephwrap_removexattr(struct vfs_handle_struct *handle,
1392 const struct smb_filename *smb_fname,
1396 DBG_DEBUG("[CEPH] removexattr(%p, %s, %s)\n", handle,
1397 smb_fname->base_name, name);
1398 ret = ceph_removexattr(handle->data, smb_fname->base_name, name);
1399 DBG_DEBUG("[CEPH] removexattr(...) = %d\n", ret);
1403 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1406 DBG_DEBUG("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name);
1407 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1408 ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1410 ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1412 DBG_DEBUG("[CEPH] fremovexattr(...) = %d\n", ret);
1416 static int cephwrap_setxattr(struct vfs_handle_struct *handle,
1417 const struct smb_filename *smb_fname,
1424 DBG_DEBUG("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle,
1425 smb_fname->base_name, name, value, llu(size), flags);
1426 ret = ceph_setxattr(handle->data, smb_fname->base_name,
1427 name, value, size, flags);
1428 DBG_DEBUG("[CEPH] setxattr(...) = %d\n", ret);
1432 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1435 DBG_DEBUG("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags);
1436 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1437 ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1438 name, value, size, flags);
1440 ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1442 DBG_DEBUG("[CEPH] fsetxattr(...) = %d\n", ret);
1446 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1450 * We do not support AIO yet.
1453 DBG_DEBUG("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp);
1458 static struct vfs_fn_pointers ceph_fns = {
1459 /* Disk operations */
1461 .connect_fn = cephwrap_connect,
1462 .disconnect_fn = cephwrap_disconnect,
1463 .disk_free_fn = cephwrap_disk_free,
1464 .get_quota_fn = cephwrap_get_quota,
1465 .set_quota_fn = cephwrap_set_quota,
1466 .statvfs_fn = cephwrap_statvfs,
1467 .fs_capabilities_fn = cephwrap_fs_capabilities,
1469 /* Directory operations */
1471 .opendir_fn = cephwrap_opendir,
1472 .fdopendir_fn = cephwrap_fdopendir,
1473 .readdir_fn = cephwrap_readdir,
1474 .seekdir_fn = cephwrap_seekdir,
1475 .telldir_fn = cephwrap_telldir,
1476 .rewind_dir_fn = cephwrap_rewinddir,
1477 .mkdir_fn = cephwrap_mkdir,
1478 .rmdir_fn = cephwrap_rmdir,
1479 .closedir_fn = cephwrap_closedir,
1481 /* File operations */
1483 .open_fn = cephwrap_open,
1484 .close_fn = cephwrap_close,
1485 .read_fn = cephwrap_read,
1486 .pread_fn = cephwrap_pread,
1487 .write_fn = cephwrap_write,
1488 .pwrite_fn = cephwrap_pwrite,
1489 .lseek_fn = cephwrap_lseek,
1490 .sendfile_fn = cephwrap_sendfile,
1491 .recvfile_fn = cephwrap_recvfile,
1492 .rename_fn = cephwrap_rename,
1493 .fsync_fn = cephwrap_fsync,
1494 .fsync_send_fn = cephwrap_fsync_send,
1495 .fsync_recv_fn = cephwrap_fsync_recv,
1496 .stat_fn = cephwrap_stat,
1497 .fstat_fn = cephwrap_fstat,
1498 .lstat_fn = cephwrap_lstat,
1499 .unlink_fn = cephwrap_unlink,
1500 .chmod_fn = cephwrap_chmod,
1501 .fchmod_fn = cephwrap_fchmod,
1502 .chown_fn = cephwrap_chown,
1503 .fchown_fn = cephwrap_fchown,
1504 .lchown_fn = cephwrap_lchown,
1505 .chdir_fn = cephwrap_chdir,
1506 .getwd_fn = cephwrap_getwd,
1507 .ntimes_fn = cephwrap_ntimes,
1508 .ftruncate_fn = cephwrap_ftruncate,
1509 .lock_fn = cephwrap_lock,
1510 .kernel_flock_fn = cephwrap_kernel_flock,
1511 .linux_setlease_fn = cephwrap_linux_setlease,
1512 .getlock_fn = cephwrap_getlock,
1513 .symlink_fn = cephwrap_symlink,
1514 .readlink_fn = cephwrap_readlink,
1515 .link_fn = cephwrap_link,
1516 .mknod_fn = cephwrap_mknod,
1517 .realpath_fn = cephwrap_realpath,
1518 .chflags_fn = cephwrap_chflags,
1519 .get_real_filename_fn = cephwrap_get_real_filename,
1520 .connectpath_fn = cephwrap_connectpath,
1522 /* EA operations. */
1523 .getxattr_fn = cephwrap_getxattr,
1524 .fgetxattr_fn = cephwrap_fgetxattr,
1525 .listxattr_fn = cephwrap_listxattr,
1526 .flistxattr_fn = cephwrap_flistxattr,
1527 .removexattr_fn = cephwrap_removexattr,
1528 .fremovexattr_fn = cephwrap_fremovexattr,
1529 .setxattr_fn = cephwrap_setxattr,
1530 .fsetxattr_fn = cephwrap_fsetxattr,
1532 /* Posix ACL Operations */
1533 .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
1534 .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
1535 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1536 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1537 .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
1538 .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
1539 .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
1541 /* aio operations */
1542 .aio_force_fn = cephwrap_aio_force,
1546 NTSTATUS vfs_ceph_init(TALLOC_CTX *ctx)
1548 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,