selftest:Samba4: report when samba is started and ready
[Samba.git] / source3 / modules / vfs_ceph.c
blobd863c8add5a9a0adcc5e59508911061f65a3bf71
1 /*
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
28 * Ceph:
30 * vfs objects = ceph [any others you need go here]
33 #include "includes.h"
34 #include "smbd/smbd.h"
35 #include <dirent.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"
42 #undef DBGC_CLASS
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)
48 #endif
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) \
60 errno = 0; \
61 if (_res < 0) { \
62 errno = -_res; \
63 return -1; \
64 } \
65 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
70 * this differently.
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
74 * connected
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
83 this possibility. */
85 static int cephwrap_connect(struct vfs_handle_struct *handle, const char *service, const char *user)
87 int ret;
88 char buf[256];
89 int snum = SNUM(handle->conn);
90 const char *conf_file;
91 const char *user_id;
93 if (cmount) {
94 handle->data = cmount; /* We have been here before */
95 cmount_cnt++;
96 return 0;
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);
105 if (ret) {
106 goto err_out;
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);
112 if (ret) {
113 goto err_cm_release;
116 DBG_DEBUG("[CEPH] calling: ceph_conf_get\n");
117 ret = ceph_conf_get(cmount, "log file", buf, sizeof(buf));
118 if (ret < 0) {
119 goto err_cm_release;
122 DBG_DEBUG("[CEPH] calling: ceph_mount\n");
123 ret = ceph_mount(cmount, NULL);
124 if (ret < 0) {
125 goto err_cm_release;
129 * encode mount context/state into our vfs/connection holding structure
130 * cmount is a ceph_mount_t*
132 handle->data = cmount;
133 cmount_cnt++;
136 * Unless we have an async implementation of getxattrat turn this off.
138 lp_do_parameter(SNUM(handle->conn), "smbd:async dosmode", "false");
140 return 0;
142 err_cm_release:
143 ceph_release(cmount);
144 cmount = NULL;
145 err_out:
147 * Handle the error correctly. Ceph returns -errno.
149 DBG_DEBUG("[CEPH] Error return: %s\n", strerror(-ret));
150 WRAP_RETURN(ret);
153 static void cephwrap_disconnect(struct vfs_handle_struct *handle)
155 int ret;
157 if (!cmount) {
158 DBG_ERR("[CEPH] Error, ceph not mounted\n");
159 return;
162 /* Should we unmount/shutdown? Only if the last disconnect? */
163 if (--cmount_cnt) {
164 DBG_DEBUG("[CEPH] Not shuting down CEPH because still more connections\n");
165 return;
168 ret = ceph_unmount(cmount);
169 if (ret < 0) {
170 DBG_ERR("[CEPH] failed to unmount: %s\n", strerror(-ret));
173 ret = ceph_release(cmount);
174 if (ret < 0) {
175 DBG_ERR("[CEPH] failed to release: %s\n", strerror(-ret));
178 cmount = NULL; /* Make it safe */
181 /* Disk operations */
183 static uint64_t cephwrap_disk_free(struct vfs_handle_struct *handle,
184 const struct smb_filename *smb_fname,
185 uint64_t *bsize,
186 uint64_t *dfree,
187 uint64_t *dsize)
189 struct statvfs statvfs_buf;
190 int ret;
192 if (!(ret = ceph_statfs(handle->data, smb_fname->base_name,
193 &statvfs_buf))) {
195 * Provide all the correct values.
197 *bsize = statvfs_buf.f_bsize;
198 *dfree = statvfs_buf.f_bavail;
199 *dsize = statvfs_buf.f_blocks;
200 DBG_DEBUG("[CEPH] bsize: %llu, dfree: %llu, dsize: %llu\n",
201 llu(*bsize), llu(*dfree), llu(*dsize));
202 return *dfree;
203 } else {
204 DBG_DEBUG("[CEPH] ceph_statfs returned %d\n", ret);
205 WRAP_RETURN(ret);
209 static int cephwrap_get_quota(struct vfs_handle_struct *handle,
210 const struct smb_filename *smb_fname,
211 enum SMB_QUOTA_TYPE qtype,
212 unid_t id,
213 SMB_DISK_QUOTA *qt)
215 /* libceph: Ceph does not implement this */
216 #if 0
217 /* was ifdef HAVE_SYS_QUOTAS */
218 int ret;
220 ret = ceph_get_quota(handle->conn->connectpath, qtype, id, qt);
222 if (ret) {
223 errno = -ret;
224 ret = -1;
227 return ret;
228 #else
229 errno = ENOSYS;
230 return -1;
231 #endif
234 static int cephwrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
236 /* libceph: Ceph does not implement this */
237 #if 0
238 /* was ifdef HAVE_SYS_QUOTAS */
239 int ret;
241 ret = ceph_set_quota(handle->conn->connectpath, qtype, id, qt);
242 if (ret) {
243 errno = -ret;
244 ret = -1;
247 return ret;
248 #else
249 WRAP_RETURN(-ENOSYS);
250 #endif
253 static int cephwrap_statvfs(struct vfs_handle_struct *handle,
254 const struct smb_filename *smb_fname,
255 vfs_statvfs_struct *statbuf)
257 struct statvfs statvfs_buf;
258 int ret;
260 ret = ceph_statfs(handle->data, smb_fname->base_name, &statvfs_buf);
261 if (ret < 0) {
262 WRAP_RETURN(ret);
263 } else {
264 statbuf->OptimalTransferSize = statvfs_buf.f_frsize;
265 statbuf->BlockSize = statvfs_buf.f_bsize;
266 statbuf->TotalBlocks = statvfs_buf.f_blocks;
267 statbuf->BlocksAvail = statvfs_buf.f_bfree;
268 statbuf->UserBlocksAvail = statvfs_buf.f_bavail;
269 statbuf->TotalFileNodes = statvfs_buf.f_files;
270 statbuf->FreeFileNodes = statvfs_buf.f_ffree;
271 statbuf->FsIdentifier = statvfs_buf.f_fsid;
272 DBG_DEBUG("[CEPH] f_bsize: %ld, f_blocks: %ld, f_bfree: %ld, f_bavail: %ld\n",
273 (long int)statvfs_buf.f_bsize, (long int)statvfs_buf.f_blocks,
274 (long int)statvfs_buf.f_bfree, (long int)statvfs_buf.f_bavail);
276 return ret;
279 static uint32_t cephwrap_fs_capabilities(struct vfs_handle_struct *handle,
280 enum timestamp_set_resolution *p_ts_res)
282 uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
284 #ifdef HAVE_CEPH_STATX
285 *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
286 #else
287 *p_ts_res = TIMESTAMP_SET_MSEC;
288 #endif
290 return caps;
293 /* Directory operations */
295 static DIR *cephwrap_opendir(struct vfs_handle_struct *handle,
296 const struct smb_filename *smb_fname,
297 const char *mask, uint32_t attr)
299 int ret = 0;
300 struct ceph_dir_result *result;
301 DBG_DEBUG("[CEPH] opendir(%p, %s)\n", handle, smb_fname->base_name);
303 /* Returns NULL if it does not exist or there are problems ? */
304 ret = ceph_opendir(handle->data, smb_fname->base_name, &result);
305 if (ret < 0) {
306 result = NULL;
307 errno = -ret; /* We return result which is NULL in this case */
310 DBG_DEBUG("[CEPH] opendir(...) = %d\n", ret);
311 return (DIR *) result;
314 static DIR *cephwrap_fdopendir(struct vfs_handle_struct *handle,
315 struct files_struct *fsp,
316 const char *mask,
317 uint32_t attributes)
319 int ret = 0;
320 struct ceph_dir_result *result;
321 DBG_DEBUG("[CEPH] fdopendir(%p, %p)\n", handle, fsp);
323 ret = ceph_opendir(handle->data, fsp->fsp_name->base_name, &result);
324 if (ret < 0) {
325 result = NULL;
326 errno = -ret; /* We return result which is NULL in this case */
329 DBG_DEBUG("[CEPH] fdopendir(...) = %d\n", ret);
330 return (DIR *) result;
333 static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
334 DIR *dirp,
335 SMB_STRUCT_STAT *sbuf)
337 struct dirent *result;
339 DBG_DEBUG("[CEPH] readdir(%p, %p)\n", handle, dirp);
340 result = ceph_readdir(handle->data, (struct ceph_dir_result *) dirp);
341 DBG_DEBUG("[CEPH] readdir(...) = %p\n", result);
343 /* Default Posix readdir() does not give us stat info.
344 * Set to invalid to indicate we didn't return this info. */
345 if (sbuf)
346 SET_STAT_INVALID(*sbuf);
347 return result;
350 static void cephwrap_seekdir(struct vfs_handle_struct *handle, DIR *dirp, long offset)
352 DBG_DEBUG("[CEPH] seekdir(%p, %p, %ld)\n", handle, dirp, offset);
353 ceph_seekdir(handle->data, (struct ceph_dir_result *) dirp, offset);
356 static long cephwrap_telldir(struct vfs_handle_struct *handle, DIR *dirp)
358 long ret;
359 DBG_DEBUG("[CEPH] telldir(%p, %p)\n", handle, dirp);
360 ret = ceph_telldir(handle->data, (struct ceph_dir_result *) dirp);
361 DBG_DEBUG("[CEPH] telldir(...) = %ld\n", ret);
362 WRAP_RETURN(ret);
365 static void cephwrap_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
367 DBG_DEBUG("[CEPH] rewinddir(%p, %p)\n", handle, dirp);
368 ceph_rewinddir(handle->data, (struct ceph_dir_result *) dirp);
371 static int cephwrap_mkdir(struct vfs_handle_struct *handle,
372 const struct smb_filename *smb_fname,
373 mode_t mode)
375 int result;
376 char *parent = NULL;
377 const char *path = smb_fname->base_name;
379 DBG_DEBUG("[CEPH] mkdir(%p, %s)\n", handle, path);
381 if (lp_inherit_acls(SNUM(handle->conn))
382 && parent_dirname(talloc_tos(), path, &parent, NULL)
383 && directory_has_default_acl(handle->conn, parent)) {
384 mode = 0777;
387 TALLOC_FREE(parent);
389 result = ceph_mkdir(handle->data, path, mode);
390 return WRAP_RETURN(result);
393 static int cephwrap_rmdir(struct vfs_handle_struct *handle,
394 const struct smb_filename *smb_fname)
396 int result;
398 DBG_DEBUG("[CEPH] rmdir(%p, %s)\n", handle, smb_fname->base_name);
399 result = ceph_rmdir(handle->data, smb_fname->base_name);
400 DBG_DEBUG("[CEPH] rmdir(...) = %d\n", result);
401 WRAP_RETURN(result);
404 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
406 int result;
408 DBG_DEBUG("[CEPH] closedir(%p, %p)\n", handle, dirp);
409 result = ceph_closedir(handle->data, (struct ceph_dir_result *) dirp);
410 DBG_DEBUG("[CEPH] closedir(...) = %d\n", result);
411 WRAP_RETURN(result);
414 /* File operations */
416 static int cephwrap_open(struct vfs_handle_struct *handle,
417 struct smb_filename *smb_fname,
418 files_struct *fsp, int flags, mode_t mode)
420 int result = -ENOENT;
421 DBG_DEBUG("[CEPH] open(%p, %s, %p, %d, %d)\n", handle,
422 smb_fname_str_dbg(smb_fname), fsp, flags, mode);
424 if (smb_fname->stream_name) {
425 goto out;
428 result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
429 out:
430 DBG_DEBUG("[CEPH] open(...) = %d\n", result);
431 WRAP_RETURN(result);
434 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
436 int result;
438 DBG_DEBUG("[CEPH] close(%p, %p)\n", handle, fsp);
439 result = ceph_close(handle->data, fsp->fh->fd);
440 DBG_DEBUG("[CEPH] close(...) = %d\n", result);
442 WRAP_RETURN(result);
445 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
446 size_t n, off_t offset)
448 ssize_t result;
450 DBG_DEBUG("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
452 result = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
453 DBG_DEBUG("[CEPH] pread(...) = %llu\n", llu(result));
454 WRAP_RETURN(result);
457 struct cephwrap_pread_state {
458 ssize_t bytes_read;
459 struct vfs_aio_state vfs_aio_state;
463 * Fake up an async ceph read by calling the synchronous API.
465 static struct tevent_req *cephwrap_pread_send(struct vfs_handle_struct *handle,
466 TALLOC_CTX *mem_ctx,
467 struct tevent_context *ev,
468 struct files_struct *fsp,
469 void *data,
470 size_t n, off_t offset)
472 struct tevent_req *req = NULL;
473 struct cephwrap_pread_state *state = NULL;
474 int ret = -1;
476 DBG_DEBUG("[CEPH] %s\n", __func__);
477 req = tevent_req_create(mem_ctx, &state, struct cephwrap_pread_state);
478 if (req == NULL) {
479 return NULL;
482 ret = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
483 if (ret < 0) {
484 /* ceph returns -errno on error. */
485 tevent_req_error(req, -ret);
486 return tevent_req_post(req, ev);
489 state->bytes_read = ret;
490 tevent_req_done(req);
491 /* Return and schedule the completion of the call. */
492 return tevent_req_post(req, ev);
495 static ssize_t cephwrap_pread_recv(struct tevent_req *req,
496 struct vfs_aio_state *vfs_aio_state)
498 struct cephwrap_pread_state *state =
499 tevent_req_data(req, struct cephwrap_pread_state);
501 DBG_DEBUG("[CEPH] %s\n", __func__);
502 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
503 return -1;
505 *vfs_aio_state = state->vfs_aio_state;
506 return state->bytes_read;
509 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
510 size_t n, off_t offset)
512 ssize_t result;
514 DBG_DEBUG("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
515 result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
516 DBG_DEBUG("[CEPH] pwrite(...) = %llu\n", llu(result));
517 WRAP_RETURN(result);
520 struct cephwrap_pwrite_state {
521 ssize_t bytes_written;
522 struct vfs_aio_state vfs_aio_state;
526 * Fake up an async ceph write by calling the synchronous API.
528 static struct tevent_req *cephwrap_pwrite_send(struct vfs_handle_struct *handle,
529 TALLOC_CTX *mem_ctx,
530 struct tevent_context *ev,
531 struct files_struct *fsp,
532 const void *data,
533 size_t n, off_t offset)
535 struct tevent_req *req = NULL;
536 struct cephwrap_pwrite_state *state = NULL;
537 int ret = -1;
539 DBG_DEBUG("[CEPH] %s\n", __func__);
540 req = tevent_req_create(mem_ctx, &state, struct cephwrap_pwrite_state);
541 if (req == NULL) {
542 return NULL;
545 ret = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
546 if (ret < 0) {
547 /* ceph returns -errno on error. */
548 tevent_req_error(req, -ret);
549 return tevent_req_post(req, ev);
552 state->bytes_written = ret;
553 tevent_req_done(req);
554 /* Return and schedule the completion of the call. */
555 return tevent_req_post(req, ev);
558 static ssize_t cephwrap_pwrite_recv(struct tevent_req *req,
559 struct vfs_aio_state *vfs_aio_state)
561 struct cephwrap_pwrite_state *state =
562 tevent_req_data(req, struct cephwrap_pwrite_state);
564 DBG_DEBUG("[CEPH] %s\n", __func__);
565 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
566 return -1;
568 *vfs_aio_state = state->vfs_aio_state;
569 return state->bytes_written;
572 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
574 off_t result = 0;
576 DBG_DEBUG("[CEPH] cephwrap_lseek\n");
577 /* Cope with 'stat' file opens. */
578 if (fsp->fh->fd != -1) {
579 result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
581 WRAP_RETURN(result);
584 static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
585 off_t offset, size_t n)
588 * We cannot support sendfile because libceph is in user space.
590 DBG_DEBUG("[CEPH] cephwrap_sendfile\n");
591 errno = ENOTSUP;
592 return -1;
595 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
596 int fromfd,
597 files_struct *tofsp,
598 off_t offset,
599 size_t n)
602 * We cannot support recvfile because libceph is in user space.
604 DBG_DEBUG("[CEPH] cephwrap_recvfile\n");
605 errno=ENOTSUP;
606 return -1;
609 static int cephwrap_rename(struct vfs_handle_struct *handle,
610 const struct smb_filename *smb_fname_src,
611 const struct smb_filename *smb_fname_dst)
613 int result = -1;
614 DBG_DEBUG("[CEPH] cephwrap_rename\n");
615 if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
616 errno = ENOENT;
617 return result;
620 result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
621 WRAP_RETURN(result);
625 * Fake up an async ceph fsync by calling the synchronous API.
628 static struct tevent_req *cephwrap_fsync_send(struct vfs_handle_struct *handle,
629 TALLOC_CTX *mem_ctx,
630 struct tevent_context *ev,
631 files_struct *fsp)
633 struct tevent_req *req = NULL;
634 struct vfs_aio_state *state = NULL;
635 int ret = -1;
637 DBG_DEBUG("[CEPH] cephwrap_fsync_send\n");
639 req = tevent_req_create(mem_ctx, &state, struct vfs_aio_state);
640 if (req == NULL) {
641 return NULL;
644 /* Make sync call. */
645 ret = ceph_fsync(handle->data, fsp->fh->fd, false);
647 if (ret != 0) {
648 /* ceph_fsync returns -errno on error. */
649 tevent_req_error(req, -ret);
650 return tevent_req_post(req, ev);
653 /* Mark it as done. */
654 tevent_req_done(req);
655 /* Return and schedule the completion of the call. */
656 return tevent_req_post(req, ev);
659 static int cephwrap_fsync_recv(struct tevent_req *req,
660 struct vfs_aio_state *vfs_aio_state)
662 struct vfs_aio_state *state =
663 tevent_req_data(req, struct vfs_aio_state);
665 DBG_DEBUG("[CEPH] cephwrap_fsync_recv\n");
667 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
668 return -1;
670 *vfs_aio_state = *state;
671 return 0;
674 #ifdef HAVE_CEPH_STATX
675 #define SAMBA_STATX_ATTR_MASK (CEPH_STATX_BASIC_STATS|CEPH_STATX_BTIME)
677 static void init_stat_ex_from_ceph_statx(struct stat_ex *dst, const struct ceph_statx *stx)
679 if ((stx->stx_mask & SAMBA_STATX_ATTR_MASK) != SAMBA_STATX_ATTR_MASK)
680 DBG_WARNING("%s: stx->stx_mask is incorrect (wanted %x, got %x)",
681 __func__, SAMBA_STATX_ATTR_MASK, stx->stx_mask);
683 dst->st_ex_dev = stx->stx_dev;
684 dst->st_ex_rdev = stx->stx_rdev;
685 dst->st_ex_ino = stx->stx_ino;
686 dst->st_ex_mode = stx->stx_mode;
687 dst->st_ex_uid = stx->stx_uid;
688 dst->st_ex_gid = stx->stx_gid;
689 dst->st_ex_size = stx->stx_size;
690 dst->st_ex_nlink = stx->stx_nlink;
691 dst->st_ex_atime = stx->stx_atime;
692 dst->st_ex_btime = stx->stx_btime;
693 dst->st_ex_ctime = stx->stx_ctime;
694 dst->st_ex_mtime = stx->stx_mtime;
695 dst->st_ex_calculated_birthtime = false;
696 dst->st_ex_blksize = stx->stx_blksize;
697 dst->st_ex_blocks = stx->stx_blocks;
700 static int cephwrap_stat(struct vfs_handle_struct *handle,
701 struct smb_filename *smb_fname)
703 int result = -1;
704 struct ceph_statx stx;
706 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
708 if (smb_fname->stream_name) {
709 errno = ENOENT;
710 return result;
713 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
714 SAMBA_STATX_ATTR_MASK, 0);
715 DBG_DEBUG("[CEPH] statx(...) = %d\n", result);
716 if (result < 0) {
717 WRAP_RETURN(result);
718 } else {
719 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
720 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
721 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
722 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
723 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
724 llu(stx.stx_size), llu(stx.stx_blksize),
725 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
726 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
728 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
729 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
730 return result;
733 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
735 int result = -1;
736 struct ceph_statx stx;
738 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
739 result = ceph_fstatx(handle->data, fsp->fh->fd, &stx,
740 SAMBA_STATX_ATTR_MASK, 0);
741 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
742 if (result < 0) {
743 WRAP_RETURN(result);
744 } else {
745 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
746 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
747 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
748 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
749 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
750 llu(stx.stx_size), llu(stx.stx_blksize),
751 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
752 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
754 init_stat_ex_from_ceph_statx(sbuf, &stx);
755 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
756 return result;
759 static int cephwrap_lstat(struct vfs_handle_struct *handle,
760 struct smb_filename *smb_fname)
762 int result = -1;
763 struct ceph_statx stx;
765 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
767 if (smb_fname->stream_name) {
768 errno = ENOENT;
769 return result;
772 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
773 SAMBA_STATX_ATTR_MASK, AT_SYMLINK_NOFOLLOW);
774 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
775 if (result < 0) {
776 WRAP_RETURN(result);
778 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
779 return result;
782 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
783 const struct smb_filename *smb_fname,
784 struct smb_file_time *ft)
786 struct ceph_statx stx = { 0 };
787 int result;
788 int mask = 0;
790 if (!null_timespec(ft->atime)) {
791 stx.stx_atime = ft->atime;
792 mask |= CEPH_SETATTR_ATIME;
794 if (!null_timespec(ft->mtime)) {
795 stx.stx_mtime = ft->mtime;
796 mask |= CEPH_SETATTR_MTIME;
798 if (!null_timespec(ft->create_time)) {
799 stx.stx_btime = ft->create_time;
800 mask |= CEPH_SETATTR_BTIME;
803 if (!mask) {
804 return 0;
807 result = ceph_setattrx(handle->data, smb_fname->base_name, &stx, mask, 0);
808 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
809 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
810 ft->create_time.tv_sec, result);
811 return result;
814 #else /* HAVE_CEPH_STATX */
816 static int cephwrap_stat(struct vfs_handle_struct *handle,
817 struct smb_filename *smb_fname)
819 int result = -1;
820 struct stat stbuf;
822 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
824 if (smb_fname->stream_name) {
825 errno = ENOENT;
826 return result;
829 result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
830 DBG_DEBUG("[CEPH] stat(...) = %d\n", result);
831 if (result < 0) {
832 WRAP_RETURN(result);
833 } else {
834 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
835 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
836 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
837 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
838 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
839 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
841 init_stat_ex_from_stat(
842 &smb_fname->st, &stbuf,
843 lp_fake_directory_create_times(SNUM(handle->conn)));
844 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
845 return result;
848 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
850 int result = -1;
851 struct stat stbuf;
853 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
854 result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
855 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
856 if (result < 0) {
857 WRAP_RETURN(result);
858 } else {
859 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
860 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
861 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
862 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
863 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
864 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
867 init_stat_ex_from_stat(
868 sbuf, &stbuf,
869 lp_fake_directory_create_times(SNUM(handle->conn)));
870 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
871 return result;
874 static int cephwrap_lstat(struct vfs_handle_struct *handle,
875 struct smb_filename *smb_fname)
877 int result = -1;
878 struct stat stbuf;
880 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
882 if (smb_fname->stream_name) {
883 errno = ENOENT;
884 return result;
887 result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
888 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
889 if (result < 0) {
890 WRAP_RETURN(result);
892 init_stat_ex_from_stat(
893 &smb_fname->st, &stbuf,
894 lp_fake_directory_create_times(SNUM(handle->conn)));
895 return result;
898 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
899 const struct smb_filename *smb_fname,
900 struct smb_file_time *ft)
902 struct utimbuf buf;
903 int result;
905 if (null_timespec(ft->atime)) {
906 buf.actime = smb_fname->st.st_ex_atime.tv_sec;
907 } else {
908 buf.actime = ft->atime.tv_sec;
910 if (null_timespec(ft->mtime)) {
911 buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
912 } else {
913 buf.modtime = ft->mtime.tv_sec;
915 if (!null_timespec(ft->create_time)) {
916 set_create_timespec_ea(handle->conn, smb_fname,
917 ft->create_time);
919 if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
920 buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
921 return 0;
924 result = ceph_utime(handle->data, smb_fname->base_name, &buf);
925 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
926 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
927 ft->create_time.tv_sec, result);
928 return result;
930 #endif /* HAVE_CEPH_STATX */
932 static int cephwrap_unlink(struct vfs_handle_struct *handle,
933 const struct smb_filename *smb_fname)
935 int result = -1;
937 DBG_DEBUG("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
938 if (smb_fname->stream_name) {
939 errno = ENOENT;
940 return result;
942 result = ceph_unlink(handle->data, smb_fname->base_name);
943 DBG_DEBUG("[CEPH] unlink(...) = %d\n", result);
944 WRAP_RETURN(result);
947 static int cephwrap_chmod(struct vfs_handle_struct *handle,
948 const struct smb_filename *smb_fname,
949 mode_t mode)
951 int result;
953 DBG_DEBUG("[CEPH] chmod(%p, %s, %d)\n", handle, smb_fname->base_name, mode);
954 result = ceph_chmod(handle->data, smb_fname->base_name, mode);
955 DBG_DEBUG("[CEPH] chmod(...) = %d\n", result);
956 WRAP_RETURN(result);
959 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
961 int result;
963 DBG_DEBUG("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode);
965 #if defined(HAVE_FCHMOD)
966 result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
967 DBG_DEBUG("[CEPH] fchmod(...) = %d\n", result);
968 WRAP_RETURN(result);
969 #else
970 errno = ENOSYS;
971 #endif
972 return -1;
975 static int cephwrap_chown(struct vfs_handle_struct *handle,
976 const struct smb_filename *smb_fname,
977 uid_t uid,
978 gid_t gid)
980 int result;
981 DBG_DEBUG("[CEPH] chown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
982 result = ceph_chown(handle->data, smb_fname->base_name, uid, gid);
983 DBG_DEBUG("[CEPH] chown(...) = %d\n", result);
984 WRAP_RETURN(result);
987 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
989 int result;
990 #ifdef HAVE_FCHOWN
992 DBG_DEBUG("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid);
993 result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
994 DBG_DEBUG("[CEPH] fchown(...) = %d\n", result);
995 WRAP_RETURN(result);
996 #else
997 errno = ENOSYS;
998 result = -1;
999 #endif
1000 return result;
1003 static int cephwrap_lchown(struct vfs_handle_struct *handle,
1004 const struct smb_filename *smb_fname,
1005 uid_t uid,
1006 gid_t gid)
1008 int result;
1009 DBG_DEBUG("[CEPH] lchown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
1010 result = ceph_lchown(handle->data, smb_fname->base_name, uid, gid);
1011 DBG_DEBUG("[CEPH] lchown(...) = %d\n", result);
1012 WRAP_RETURN(result);
1015 static int cephwrap_chdir(struct vfs_handle_struct *handle,
1016 const struct smb_filename *smb_fname)
1018 int result = -1;
1019 DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, smb_fname->base_name);
1020 result = ceph_chdir(handle->data, smb_fname->base_name);
1021 DBG_DEBUG("[CEPH] chdir(...) = %d\n", result);
1022 WRAP_RETURN(result);
1025 static struct smb_filename *cephwrap_getwd(struct vfs_handle_struct *handle,
1026 TALLOC_CTX *ctx)
1028 const char *cwd = ceph_getcwd(handle->data);
1029 DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd);
1030 return synthetic_smb_fname(ctx,
1031 cwd,
1032 NULL,
1033 NULL,
1037 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1039 off_t space_to_write;
1040 uint64_t space_avail;
1041 uint64_t bsize,dfree,dsize;
1042 int ret;
1043 NTSTATUS status;
1044 SMB_STRUCT_STAT *pst;
1046 status = vfs_stat_fsp(fsp);
1047 if (!NT_STATUS_IS_OK(status)) {
1048 return -1;
1050 pst = &fsp->fsp_name->st;
1052 #ifdef S_ISFIFO
1053 if (S_ISFIFO(pst->st_ex_mode))
1054 return 0;
1055 #endif
1057 if (pst->st_ex_size == len)
1058 return 0;
1060 /* Shrink - just ftruncate. */
1061 if (pst->st_ex_size > len)
1062 return ftruncate(fsp->fh->fd, len);
1064 space_to_write = len - pst->st_ex_size;
1066 /* for allocation try fallocate first. This can fail on some
1067 platforms e.g. when the filesystem doesn't support it and no
1068 emulation is being done by the libc (like on AIX with JFS1). In that
1069 case we do our own emulation. fallocate implementations can
1070 return ENOTSUP or EINVAL in cases like that. */
1071 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
1072 if (ret == -1 && errno == ENOSPC) {
1073 return -1;
1075 if (ret == 0) {
1076 return 0;
1078 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
1079 "error %d. Falling back to slow manual allocation\n", errno));
1081 /* available disk space is enough or not? */
1082 space_avail =
1083 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
1084 /* space_avail is 1k blocks */
1085 if (space_avail == (uint64_t)-1 ||
1086 ((uint64_t)space_to_write/1024 > space_avail) ) {
1087 errno = ENOSPC;
1088 return -1;
1091 /* Write out the real space on disk. */
1092 return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
1095 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1097 int result = -1;
1098 SMB_STRUCT_STAT st;
1099 char c = 0;
1100 off_t currpos;
1102 DBG_DEBUG("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len));
1104 if (lp_strict_allocate(SNUM(fsp->conn))) {
1105 result = strict_allocate_ftruncate(handle, fsp, len);
1106 return result;
1109 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
1110 sys_ftruncate if the system supports it. Then I discovered that
1111 you can have some filesystems that support ftruncate
1112 expansion and some that don't! On Linux fat can't do
1113 ftruncate extend but ext2 can. */
1115 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1116 if (result == 0)
1117 goto done;
1119 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
1120 extend a file with ftruncate. Provide alternate implementation
1121 for this */
1122 currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
1123 if (currpos == -1) {
1124 goto done;
1127 /* Do an fstat to see if the file is longer than the requested
1128 size in which case the ftruncate above should have
1129 succeeded or shorter, in which case seek to len - 1 and
1130 write 1 byte of zero */
1131 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
1132 goto done;
1135 #ifdef S_ISFIFO
1136 if (S_ISFIFO(st.st_ex_mode)) {
1137 result = 0;
1138 goto done;
1140 #endif
1142 if (st.st_ex_size == len) {
1143 result = 0;
1144 goto done;
1147 if (st.st_ex_size > len) {
1148 /* the sys_ftruncate should have worked */
1149 goto done;
1152 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
1153 goto done;
1156 result = 0;
1158 done:
1160 return result;
1163 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
1165 DBG_DEBUG("[CEPH] lock\n");
1166 return true;
1169 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
1170 uint32_t share_mode, uint32_t access_mask)
1172 DBG_ERR("[CEPH] flock unsupported! Consider setting "
1173 "\"kernel share modes = no\"\n");
1175 errno = ENOSYS;
1176 return -1;
1179 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
1181 DBG_DEBUG("[CEPH] getlock returning false and errno=0\n");
1183 errno = 0;
1184 return false;
1188 * We cannot let this fall through to the default, because the file might only
1189 * be accessible from libceph (which is a user-space client) but the fd might
1190 * be for some file the kernel knows about.
1192 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
1193 int leasetype)
1195 int result = -1;
1197 DBG_DEBUG("[CEPH] linux_setlease\n");
1198 errno = ENOSYS;
1199 return result;
1202 static int cephwrap_symlink(struct vfs_handle_struct *handle,
1203 const char *link_target,
1204 const struct smb_filename *new_smb_fname)
1206 int result = -1;
1207 DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle,
1208 link_target,
1209 new_smb_fname->base_name);
1210 result = ceph_symlink(handle->data,
1211 link_target,
1212 new_smb_fname->base_name);
1213 DBG_DEBUG("[CEPH] symlink(...) = %d\n", result);
1214 WRAP_RETURN(result);
1217 static int cephwrap_readlink(struct vfs_handle_struct *handle,
1218 const struct smb_filename *smb_fname,
1219 char *buf,
1220 size_t bufsiz)
1222 int result = -1;
1223 DBG_DEBUG("[CEPH] readlink(%p, %s, %p, %llu)\n", handle,
1224 smb_fname->base_name, buf, llu(bufsiz));
1225 result = ceph_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1226 DBG_DEBUG("[CEPH] readlink(...) = %d\n", result);
1227 WRAP_RETURN(result);
1230 static int cephwrap_link(struct vfs_handle_struct *handle,
1231 const struct smb_filename *old_smb_fname,
1232 const struct smb_filename *new_smb_fname)
1234 int result = -1;
1235 DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle,
1236 old_smb_fname->base_name,
1237 new_smb_fname->base_name);
1238 result = ceph_link(handle->data,
1239 old_smb_fname->base_name,
1240 new_smb_fname->base_name);
1241 DBG_DEBUG("[CEPH] link(...) = %d\n", result);
1242 WRAP_RETURN(result);
1245 static int cephwrap_mknod(struct vfs_handle_struct *handle,
1246 const struct smb_filename *smb_fname,
1247 mode_t mode,
1248 SMB_DEV_T dev)
1250 int result = -1;
1251 DBG_DEBUG("[CEPH] mknod(%p, %s)\n", handle, smb_fname->base_name);
1252 result = ceph_mknod(handle->data, smb_fname->base_name, mode, dev);
1253 DBG_DEBUG("[CEPH] mknod(...) = %d\n", result);
1254 WRAP_RETURN(result);
1258 * This is a simple version of real-path ... a better version is needed to
1259 * ask libceph about symbolic links.
1261 static struct smb_filename *cephwrap_realpath(struct vfs_handle_struct *handle,
1262 TALLOC_CTX *ctx,
1263 const struct smb_filename *smb_fname)
1265 char *result = NULL;
1266 const char *path = smb_fname->base_name;
1267 size_t len = strlen(path);
1268 struct smb_filename *result_fname = NULL;
1269 int r = -1;
1271 if (len && (path[0] == '/')) {
1272 r = asprintf(&result, "%s", path);
1273 } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1274 if (len == 2) {
1275 r = asprintf(&result, "%s",
1276 handle->conn->connectpath);
1277 } else {
1278 r = asprintf(&result, "%s/%s",
1279 handle->conn->connectpath, &path[2]);
1281 } else {
1282 r = asprintf(&result, "%s/%s",
1283 handle->conn->connectpath, path);
1286 if (r < 0) {
1287 return NULL;
1290 DBG_DEBUG("[CEPH] realpath(%p, %s) = %s\n", handle, path, result);
1291 result_fname = synthetic_smb_fname(ctx,
1292 result,
1293 NULL,
1294 NULL,
1296 SAFE_FREE(result);
1297 return result_fname;
1300 static int cephwrap_chflags(struct vfs_handle_struct *handle,
1301 const struct smb_filename *smb_fname,
1302 unsigned int flags)
1304 errno = ENOSYS;
1305 return -1;
1308 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1309 const char *path,
1310 const char *name,
1311 TALLOC_CTX *mem_ctx,
1312 char **found_name)
1315 * Don't fall back to get_real_filename so callers can differentiate
1316 * between a full directory scan and an actual case-insensitive stat.
1318 errno = EOPNOTSUPP;
1319 return -1;
1322 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1323 const struct smb_filename *smb_fname)
1325 return handle->conn->connectpath;
1328 /****************************************************************
1329 Extended attribute operations.
1330 *****************************************************************/
1332 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,
1333 const struct smb_filename *smb_fname,
1334 const char *name,
1335 void *value,
1336 size_t size)
1338 int ret;
1339 DBG_DEBUG("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle,
1340 smb_fname->base_name, name, value, llu(size));
1341 ret = ceph_getxattr(handle->data,
1342 smb_fname->base_name, name, value, size);
1343 DBG_DEBUG("[CEPH] getxattr(...) = %d\n", ret);
1344 if (ret < 0) {
1345 WRAP_RETURN(ret);
1346 } else {
1347 return (ssize_t)ret;
1351 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1353 int ret;
1354 DBG_DEBUG("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size));
1355 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1356 ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1357 #else
1358 ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1359 #endif
1360 DBG_DEBUG("[CEPH] fgetxattr(...) = %d\n", ret);
1361 if (ret < 0) {
1362 WRAP_RETURN(ret);
1363 } else {
1364 return (ssize_t)ret;
1368 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle,
1369 const struct smb_filename *smb_fname,
1370 char *list,
1371 size_t size)
1373 int ret;
1374 DBG_DEBUG("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle,
1375 smb_fname->base_name, list, llu(size));
1376 ret = ceph_listxattr(handle->data, smb_fname->base_name, list, size);
1377 DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
1378 if (ret < 0) {
1379 WRAP_RETURN(ret);
1380 } else {
1381 return (ssize_t)ret;
1385 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1387 int ret;
1388 DBG_DEBUG("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size));
1389 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1390 ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1391 #else
1392 ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1393 #endif
1394 DBG_DEBUG("[CEPH] flistxattr(...) = %d\n", ret);
1395 if (ret < 0) {
1396 WRAP_RETURN(ret);
1397 } else {
1398 return (ssize_t)ret;
1402 static int cephwrap_removexattr(struct vfs_handle_struct *handle,
1403 const struct smb_filename *smb_fname,
1404 const char *name)
1406 int ret;
1407 DBG_DEBUG("[CEPH] removexattr(%p, %s, %s)\n", handle,
1408 smb_fname->base_name, name);
1409 ret = ceph_removexattr(handle->data, smb_fname->base_name, name);
1410 DBG_DEBUG("[CEPH] removexattr(...) = %d\n", ret);
1411 WRAP_RETURN(ret);
1414 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1416 int ret;
1417 DBG_DEBUG("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name);
1418 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1419 ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1420 #else
1421 ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1422 #endif
1423 DBG_DEBUG("[CEPH] fremovexattr(...) = %d\n", ret);
1424 WRAP_RETURN(ret);
1427 static int cephwrap_setxattr(struct vfs_handle_struct *handle,
1428 const struct smb_filename *smb_fname,
1429 const char *name,
1430 const void *value,
1431 size_t size,
1432 int flags)
1434 int ret;
1435 DBG_DEBUG("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle,
1436 smb_fname->base_name, name, value, llu(size), flags);
1437 ret = ceph_setxattr(handle->data, smb_fname->base_name,
1438 name, value, size, flags);
1439 DBG_DEBUG("[CEPH] setxattr(...) = %d\n", ret);
1440 WRAP_RETURN(ret);
1443 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1445 int ret;
1446 DBG_DEBUG("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags);
1447 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1448 ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1449 name, value, size, flags);
1450 #else
1451 ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1452 #endif
1453 DBG_DEBUG("[CEPH] fsetxattr(...) = %d\n", ret);
1454 WRAP_RETURN(ret);
1457 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1461 * We do not support AIO yet.
1464 DBG_DEBUG("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp);
1465 errno = ENOTSUP;
1466 return false;
1469 static struct vfs_fn_pointers ceph_fns = {
1470 /* Disk operations */
1472 .connect_fn = cephwrap_connect,
1473 .disconnect_fn = cephwrap_disconnect,
1474 .disk_free_fn = cephwrap_disk_free,
1475 .get_quota_fn = cephwrap_get_quota,
1476 .set_quota_fn = cephwrap_set_quota,
1477 .statvfs_fn = cephwrap_statvfs,
1478 .fs_capabilities_fn = cephwrap_fs_capabilities,
1480 /* Directory operations */
1482 .opendir_fn = cephwrap_opendir,
1483 .fdopendir_fn = cephwrap_fdopendir,
1484 .readdir_fn = cephwrap_readdir,
1485 .seekdir_fn = cephwrap_seekdir,
1486 .telldir_fn = cephwrap_telldir,
1487 .rewind_dir_fn = cephwrap_rewinddir,
1488 .mkdir_fn = cephwrap_mkdir,
1489 .rmdir_fn = cephwrap_rmdir,
1490 .closedir_fn = cephwrap_closedir,
1492 /* File operations */
1494 .open_fn = cephwrap_open,
1495 .close_fn = cephwrap_close,
1496 .pread_fn = cephwrap_pread,
1497 .pread_send_fn = cephwrap_pread_send,
1498 .pread_recv_fn = cephwrap_pread_recv,
1499 .pwrite_fn = cephwrap_pwrite,
1500 .pwrite_send_fn = cephwrap_pwrite_send,
1501 .pwrite_recv_fn = cephwrap_pwrite_recv,
1502 .lseek_fn = cephwrap_lseek,
1503 .sendfile_fn = cephwrap_sendfile,
1504 .recvfile_fn = cephwrap_recvfile,
1505 .rename_fn = cephwrap_rename,
1506 .fsync_send_fn = cephwrap_fsync_send,
1507 .fsync_recv_fn = cephwrap_fsync_recv,
1508 .stat_fn = cephwrap_stat,
1509 .fstat_fn = cephwrap_fstat,
1510 .lstat_fn = cephwrap_lstat,
1511 .unlink_fn = cephwrap_unlink,
1512 .chmod_fn = cephwrap_chmod,
1513 .fchmod_fn = cephwrap_fchmod,
1514 .chown_fn = cephwrap_chown,
1515 .fchown_fn = cephwrap_fchown,
1516 .lchown_fn = cephwrap_lchown,
1517 .chdir_fn = cephwrap_chdir,
1518 .getwd_fn = cephwrap_getwd,
1519 .ntimes_fn = cephwrap_ntimes,
1520 .ftruncate_fn = cephwrap_ftruncate,
1521 .lock_fn = cephwrap_lock,
1522 .kernel_flock_fn = cephwrap_kernel_flock,
1523 .linux_setlease_fn = cephwrap_linux_setlease,
1524 .getlock_fn = cephwrap_getlock,
1525 .symlink_fn = cephwrap_symlink,
1526 .readlink_fn = cephwrap_readlink,
1527 .link_fn = cephwrap_link,
1528 .mknod_fn = cephwrap_mknod,
1529 .realpath_fn = cephwrap_realpath,
1530 .chflags_fn = cephwrap_chflags,
1531 .get_real_filename_fn = cephwrap_get_real_filename,
1532 .connectpath_fn = cephwrap_connectpath,
1534 /* EA operations. */
1535 .getxattr_fn = cephwrap_getxattr,
1536 .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
1537 .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
1538 .fgetxattr_fn = cephwrap_fgetxattr,
1539 .listxattr_fn = cephwrap_listxattr,
1540 .flistxattr_fn = cephwrap_flistxattr,
1541 .removexattr_fn = cephwrap_removexattr,
1542 .fremovexattr_fn = cephwrap_fremovexattr,
1543 .setxattr_fn = cephwrap_setxattr,
1544 .fsetxattr_fn = cephwrap_fsetxattr,
1546 /* Posix ACL Operations */
1547 .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
1548 .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
1549 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1550 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1551 .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
1552 .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
1553 .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
1555 /* aio operations */
1556 .aio_force_fn = cephwrap_aio_force,
1559 static_decl_vfs;
1560 NTSTATUS vfs_ceph_init(TALLOC_CTX *ctx)
1562 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1563 "ceph", &ceph_fns);