Fix spelling s/Everytime/Every time/
[Samba.git] / source3 / modules / vfs_ceph.c
blobbac88581133b454a87ac48f49807f0ea36921300
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++;
135 return 0;
137 err_cm_release:
138 ceph_release(cmount);
139 cmount = NULL;
140 err_out:
142 * Handle the error correctly. Ceph returns -errno.
144 DBG_DEBUG("[CEPH] Error return: %s\n", strerror(-ret));
145 WRAP_RETURN(ret);
148 static void cephwrap_disconnect(struct vfs_handle_struct *handle)
150 int ret;
152 if (!cmount) {
153 DBG_ERR("[CEPH] Error, ceph not mounted\n");
154 return;
157 /* Should we unmount/shutdown? Only if the last disconnect? */
158 if (--cmount_cnt) {
159 DBG_DEBUG("[CEPH] Not shuting down CEPH because still more connections\n");
160 return;
163 ret = ceph_unmount(cmount);
164 if (ret < 0) {
165 DBG_ERR("[CEPH] failed to unmount: %s\n", strerror(-ret));
168 ret = ceph_release(cmount);
169 if (ret < 0) {
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,
180 uint64_t *bsize,
181 uint64_t *dfree,
182 uint64_t *dsize)
184 struct statvfs statvfs_buf;
185 int ret;
187 if (!(ret = ceph_statfs(handle->data, smb_fname->base_name,
188 &statvfs_buf))) {
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));
197 return *dfree;
198 } else {
199 DBG_DEBUG("[CEPH] ceph_statfs returned %d\n", ret);
200 WRAP_RETURN(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,
207 unid_t id,
208 SMB_DISK_QUOTA *qt)
210 /* libceph: Ceph does not implement this */
211 #if 0
212 /* was ifdef HAVE_SYS_QUOTAS */
213 int ret;
215 ret = ceph_get_quota(handle->conn->connectpath, qtype, id, qt);
217 if (ret) {
218 errno = -ret;
219 ret = -1;
222 return ret;
223 #else
224 errno = ENOSYS;
225 return -1;
226 #endif
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 */
232 #if 0
233 /* was ifdef HAVE_SYS_QUOTAS */
234 int ret;
236 ret = ceph_set_quota(handle->conn->connectpath, qtype, id, qt);
237 if (ret) {
238 errno = -ret;
239 ret = -1;
242 return ret;
243 #else
244 WRAP_RETURN(-ENOSYS);
245 #endif
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;
253 int ret;
255 ret = ceph_statfs(handle->data, smb_fname->base_name, &statvfs_buf);
256 if (ret < 0) {
257 WRAP_RETURN(ret);
258 } else {
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);
271 return ret;
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;
281 #else
282 *p_ts_res = TIMESTAMP_SET_MSEC;
283 #endif
285 return caps;
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)
294 int ret = 0;
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);
300 if (ret < 0) {
301 result = NULL;
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,
311 const char *mask,
312 uint32_t attributes)
314 int ret = 0;
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);
319 if (ret < 0) {
320 result = NULL;
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,
329 DIR *dirp,
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. */
340 if (sbuf)
341 SET_STAT_INVALID(*sbuf);
342 return result;
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)
353 long ret;
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);
357 WRAP_RETURN(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,
368 mode_t mode)
370 int result;
371 bool has_dacl = False;
372 char *parent = NULL;
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)))
380 mode = 0777;
382 TALLOC_FREE(parent);
384 result = ceph_mkdir(handle->data, path, mode);
387 * Note. This order is important
389 if (result) {
390 WRAP_RETURN(result);
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) &&
401 (errno == ENOSYS)) {
402 errno = saved_errno;
406 return result;
409 static int cephwrap_rmdir(struct vfs_handle_struct *handle,
410 const struct smb_filename *smb_fname)
412 int result;
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);
417 WRAP_RETURN(result);
420 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
422 int result;
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);
427 WRAP_RETURN(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) {
441 goto out;
444 result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
445 out:
446 DBG_DEBUG("[CEPH] open(...) = %d\n", result);
447 WRAP_RETURN(result);
450 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
452 int result;
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);
458 WRAP_RETURN(result);
461 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
462 size_t n, off_t offset)
464 ssize_t result;
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));
470 WRAP_RETURN(result);
473 struct cephwrap_pread_state {
474 ssize_t bytes_read;
475 struct vfs_aio_state vfs_aio_state;
479 * Fake up an async ceph read by calling the synchronous API.
481 static struct tevent_req *cephwrap_pread_send(struct vfs_handle_struct *handle,
482 TALLOC_CTX *mem_ctx,
483 struct tevent_context *ev,
484 struct files_struct *fsp,
485 void *data,
486 size_t n, off_t offset)
488 struct tevent_req *req = NULL;
489 struct cephwrap_pread_state *state = NULL;
490 int ret = -1;
492 DBG_DEBUG("[CEPH] %s\n", __func__);
493 req = tevent_req_create(mem_ctx, &state, struct cephwrap_pread_state);
494 if (req == NULL) {
495 return NULL;
498 ret = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
499 if (ret < 0) {
500 /* ceph returns -errno on error. */
501 tevent_req_error(req, -ret);
502 return tevent_req_post(req, ev);
505 state->bytes_read = ret;
506 tevent_req_done(req);
507 /* Return and schedule the completion of the call. */
508 return tevent_req_post(req, ev);
511 static ssize_t cephwrap_pread_recv(struct tevent_req *req,
512 struct vfs_aio_state *vfs_aio_state)
514 struct cephwrap_pread_state *state =
515 tevent_req_data(req, struct cephwrap_pread_state);
517 DBG_DEBUG("[CEPH] %s\n", __func__);
518 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
519 return -1;
521 *vfs_aio_state = state->vfs_aio_state;
522 return state->bytes_read;
525 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
526 size_t n, off_t offset)
528 ssize_t result;
530 DBG_DEBUG("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
531 result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
532 DBG_DEBUG("[CEPH] pwrite(...) = %llu\n", llu(result));
533 WRAP_RETURN(result);
536 struct cephwrap_pwrite_state {
537 ssize_t bytes_written;
538 struct vfs_aio_state vfs_aio_state;
542 * Fake up an async ceph write by calling the synchronous API.
544 static struct tevent_req *cephwrap_pwrite_send(struct vfs_handle_struct *handle,
545 TALLOC_CTX *mem_ctx,
546 struct tevent_context *ev,
547 struct files_struct *fsp,
548 const void *data,
549 size_t n, off_t offset)
551 struct tevent_req *req = NULL;
552 struct cephwrap_pwrite_state *state = NULL;
553 int ret = -1;
555 DBG_DEBUG("[CEPH] %s\n", __func__);
556 req = tevent_req_create(mem_ctx, &state, struct cephwrap_pwrite_state);
557 if (req == NULL) {
558 return NULL;
561 ret = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
562 if (ret < 0) {
563 /* ceph returns -errno on error. */
564 tevent_req_error(req, -ret);
565 return tevent_req_post(req, ev);
568 state->bytes_written = ret;
569 tevent_req_done(req);
570 /* Return and schedule the completion of the call. */
571 return tevent_req_post(req, ev);
574 static ssize_t cephwrap_pwrite_recv(struct tevent_req *req,
575 struct vfs_aio_state *vfs_aio_state)
577 struct cephwrap_pwrite_state *state =
578 tevent_req_data(req, struct cephwrap_pwrite_state);
580 DBG_DEBUG("[CEPH] %s\n", __func__);
581 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
582 return -1;
584 *vfs_aio_state = state->vfs_aio_state;
585 return state->bytes_written;
588 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
590 off_t result = 0;
592 DBG_DEBUG("[CEPH] cephwrap_lseek\n");
593 /* Cope with 'stat' file opens. */
594 if (fsp->fh->fd != -1) {
595 result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
597 WRAP_RETURN(result);
600 static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
601 off_t offset, size_t n)
604 * We cannot support sendfile because libceph is in user space.
606 DBG_DEBUG("[CEPH] cephwrap_sendfile\n");
607 errno = ENOTSUP;
608 return -1;
611 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
612 int fromfd,
613 files_struct *tofsp,
614 off_t offset,
615 size_t n)
618 * We cannot support recvfile because libceph is in user space.
620 DBG_DEBUG("[CEPH] cephwrap_recvfile\n");
621 errno=ENOTSUP;
622 return -1;
625 static int cephwrap_rename(struct vfs_handle_struct *handle,
626 const struct smb_filename *smb_fname_src,
627 const struct smb_filename *smb_fname_dst)
629 int result = -1;
630 DBG_DEBUG("[CEPH] cephwrap_rename\n");
631 if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
632 errno = ENOENT;
633 return result;
636 result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
637 WRAP_RETURN(result);
641 * Fake up an async ceph fsync by calling the synchronous API.
644 static struct tevent_req *cephwrap_fsync_send(struct vfs_handle_struct *handle,
645 TALLOC_CTX *mem_ctx,
646 struct tevent_context *ev,
647 files_struct *fsp)
649 struct tevent_req *req = NULL;
650 struct vfs_aio_state *state = NULL;
651 int ret = -1;
653 DBG_DEBUG("[CEPH] cephwrap_fsync_send\n");
655 req = tevent_req_create(mem_ctx, &state, struct vfs_aio_state);
656 if (req == NULL) {
657 return NULL;
660 /* Make sync call. */
661 ret = ceph_fsync(handle->data, fsp->fh->fd, false);
663 if (ret != 0) {
664 /* ceph_fsync returns -errno on error. */
665 tevent_req_error(req, -ret);
666 return tevent_req_post(req, ev);
669 /* Mark it as done. */
670 tevent_req_done(req);
671 /* Return and schedule the completion of the call. */
672 return tevent_req_post(req, ev);
675 static int cephwrap_fsync_recv(struct tevent_req *req,
676 struct vfs_aio_state *vfs_aio_state)
678 struct vfs_aio_state *state =
679 tevent_req_data(req, struct vfs_aio_state);
681 DBG_DEBUG("[CEPH] cephwrap_fsync_recv\n");
683 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
684 return -1;
686 *vfs_aio_state = *state;
687 return 0;
690 #ifdef HAVE_CEPH_STATX
691 #define SAMBA_STATX_ATTR_MASK (CEPH_STATX_BASIC_STATS|CEPH_STATX_BTIME)
693 static void init_stat_ex_from_ceph_statx(struct stat_ex *dst, const struct ceph_statx *stx)
695 if ((stx->stx_mask & SAMBA_STATX_ATTR_MASK) != SAMBA_STATX_ATTR_MASK)
696 DBG_WARNING("%s: stx->stx_mask is incorrect (wanted %x, got %x)",
697 __func__, SAMBA_STATX_ATTR_MASK, stx->stx_mask);
699 dst->st_ex_dev = stx->stx_dev;
700 dst->st_ex_rdev = stx->stx_rdev;
701 dst->st_ex_ino = stx->stx_ino;
702 dst->st_ex_mode = stx->stx_mode;
703 dst->st_ex_uid = stx->stx_uid;
704 dst->st_ex_gid = stx->stx_gid;
705 dst->st_ex_size = stx->stx_size;
706 dst->st_ex_nlink = stx->stx_nlink;
707 dst->st_ex_atime = stx->stx_atime;
708 dst->st_ex_btime = stx->stx_btime;
709 dst->st_ex_ctime = stx->stx_ctime;
710 dst->st_ex_mtime = stx->stx_mtime;
711 dst->st_ex_calculated_birthtime = false;
712 dst->st_ex_blksize = stx->stx_blksize;
713 dst->st_ex_blocks = stx->stx_blocks;
716 static int cephwrap_stat(struct vfs_handle_struct *handle,
717 struct smb_filename *smb_fname)
719 int result = -1;
720 struct ceph_statx stx;
722 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
724 if (smb_fname->stream_name) {
725 errno = ENOENT;
726 return result;
729 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
730 SAMBA_STATX_ATTR_MASK, 0);
731 DBG_DEBUG("[CEPH] statx(...) = %d\n", result);
732 if (result < 0) {
733 WRAP_RETURN(result);
734 } else {
735 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
736 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
737 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
738 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
739 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
740 llu(stx.stx_size), llu(stx.stx_blksize),
741 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
742 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
744 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
745 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
746 return result;
749 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
751 int result = -1;
752 struct ceph_statx stx;
754 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
755 result = ceph_fstatx(handle->data, fsp->fh->fd, &stx,
756 SAMBA_STATX_ATTR_MASK, 0);
757 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
758 if (result < 0) {
759 WRAP_RETURN(result);
760 } else {
761 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
762 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
763 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
764 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
765 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
766 llu(stx.stx_size), llu(stx.stx_blksize),
767 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
768 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
770 init_stat_ex_from_ceph_statx(sbuf, &stx);
771 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
772 return result;
775 static int cephwrap_lstat(struct vfs_handle_struct *handle,
776 struct smb_filename *smb_fname)
778 int result = -1;
779 struct ceph_statx stx;
781 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
783 if (smb_fname->stream_name) {
784 errno = ENOENT;
785 return result;
788 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
789 SAMBA_STATX_ATTR_MASK, AT_SYMLINK_NOFOLLOW);
790 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
791 if (result < 0) {
792 WRAP_RETURN(result);
794 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
795 return result;
798 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
799 const struct smb_filename *smb_fname,
800 struct smb_file_time *ft)
802 struct ceph_statx stx = { 0 };
803 int result;
804 int mask = 0;
806 if (!null_timespec(ft->atime)) {
807 stx.stx_atime = ft->atime;
808 mask |= CEPH_SETATTR_ATIME;
810 if (!null_timespec(ft->mtime)) {
811 stx.stx_mtime = ft->mtime;
812 mask |= CEPH_SETATTR_MTIME;
814 if (!null_timespec(ft->create_time)) {
815 stx.stx_btime = ft->create_time;
816 mask |= CEPH_SETATTR_BTIME;
819 if (!mask) {
820 return 0;
823 result = ceph_setattrx(handle->data, smb_fname->base_name, &stx, mask, 0);
824 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
825 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
826 ft->create_time.tv_sec, result);
827 return result;
830 #else /* HAVE_CEPH_STATX */
832 static int cephwrap_stat(struct vfs_handle_struct *handle,
833 struct smb_filename *smb_fname)
835 int result = -1;
836 struct stat stbuf;
838 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
840 if (smb_fname->stream_name) {
841 errno = ENOENT;
842 return result;
845 result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
846 DBG_DEBUG("[CEPH] stat(...) = %d\n", result);
847 if (result < 0) {
848 WRAP_RETURN(result);
849 } else {
850 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
851 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
852 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
853 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
854 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
855 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
857 init_stat_ex_from_stat(
858 &smb_fname->st, &stbuf,
859 lp_fake_directory_create_times(SNUM(handle->conn)));
860 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
861 return result;
864 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
866 int result = -1;
867 struct stat stbuf;
869 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
870 result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
871 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
872 if (result < 0) {
873 WRAP_RETURN(result);
874 } else {
875 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
876 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
877 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
878 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
879 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
880 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
883 init_stat_ex_from_stat(
884 sbuf, &stbuf,
885 lp_fake_directory_create_times(SNUM(handle->conn)));
886 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
887 return result;
890 static int cephwrap_lstat(struct vfs_handle_struct *handle,
891 struct smb_filename *smb_fname)
893 int result = -1;
894 struct stat stbuf;
896 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
898 if (smb_fname->stream_name) {
899 errno = ENOENT;
900 return result;
903 result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
904 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
905 if (result < 0) {
906 WRAP_RETURN(result);
908 init_stat_ex_from_stat(
909 &smb_fname->st, &stbuf,
910 lp_fake_directory_create_times(SNUM(handle->conn)));
911 return result;
914 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
915 const struct smb_filename *smb_fname,
916 struct smb_file_time *ft)
918 struct utimbuf buf;
919 int result;
921 if (null_timespec(ft->atime)) {
922 buf.actime = smb_fname->st.st_ex_atime.tv_sec;
923 } else {
924 buf.actime = ft->atime.tv_sec;
926 if (null_timespec(ft->mtime)) {
927 buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
928 } else {
929 buf.modtime = ft->mtime.tv_sec;
931 if (!null_timespec(ft->create_time)) {
932 set_create_timespec_ea(handle->conn, smb_fname,
933 ft->create_time);
935 if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
936 buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
937 return 0;
940 result = ceph_utime(handle->data, smb_fname->base_name, &buf);
941 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
942 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
943 ft->create_time.tv_sec, result);
944 return result;
946 #endif /* HAVE_CEPH_STATX */
948 static int cephwrap_unlink(struct vfs_handle_struct *handle,
949 const struct smb_filename *smb_fname)
951 int result = -1;
953 DBG_DEBUG("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
954 if (smb_fname->stream_name) {
955 errno = ENOENT;
956 return result;
958 result = ceph_unlink(handle->data, smb_fname->base_name);
959 DBG_DEBUG("[CEPH] unlink(...) = %d\n", result);
960 WRAP_RETURN(result);
963 static int cephwrap_chmod(struct vfs_handle_struct *handle,
964 const struct smb_filename *smb_fname,
965 mode_t mode)
967 int result;
969 DBG_DEBUG("[CEPH] chmod(%p, %s, %d)\n", handle, smb_fname->base_name, mode);
972 * We need to do this due to the fact that the default POSIX ACL
973 * chmod modifies the ACL *mask* for the group owner, not the
974 * group owner bits directly. JRA.
979 int saved_errno = errno; /* We might get ENOSYS */
980 result = SMB_VFS_CHMOD_ACL(handle->conn,
981 smb_fname,
982 mode);
983 if (result == 0) {
984 return result;
986 /* Error - return the old errno. */
987 errno = saved_errno;
990 result = ceph_chmod(handle->data, smb_fname->base_name, mode);
991 DBG_DEBUG("[CEPH] chmod(...) = %d\n", result);
992 WRAP_RETURN(result);
995 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
997 int result;
999 DBG_DEBUG("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode);
1002 * We need to do this due to the fact that the default POSIX ACL
1003 * chmod modifies the ACL *mask* for the group owner, not the
1004 * group owner bits directly. JRA.
1008 int saved_errno = errno; /* We might get ENOSYS */
1009 if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
1010 return result;
1012 /* Error - return the old errno. */
1013 errno = saved_errno;
1016 #if defined(HAVE_FCHMOD)
1017 result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
1018 DBG_DEBUG("[CEPH] fchmod(...) = %d\n", result);
1019 WRAP_RETURN(result);
1020 #else
1021 errno = ENOSYS;
1022 #endif
1023 return -1;
1026 static int cephwrap_chown(struct vfs_handle_struct *handle,
1027 const struct smb_filename *smb_fname,
1028 uid_t uid,
1029 gid_t gid)
1031 int result;
1032 DBG_DEBUG("[CEPH] chown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
1033 result = ceph_chown(handle->data, smb_fname->base_name, uid, gid);
1034 DBG_DEBUG("[CEPH] chown(...) = %d\n", result);
1035 WRAP_RETURN(result);
1038 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
1040 int result;
1041 #ifdef HAVE_FCHOWN
1043 DBG_DEBUG("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid);
1044 result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
1045 DBG_DEBUG("[CEPH] fchown(...) = %d\n", result);
1046 WRAP_RETURN(result);
1047 #else
1048 errno = ENOSYS;
1049 result = -1;
1050 #endif
1051 return result;
1054 static int cephwrap_lchown(struct vfs_handle_struct *handle,
1055 const struct smb_filename *smb_fname,
1056 uid_t uid,
1057 gid_t gid)
1059 int result;
1060 DBG_DEBUG("[CEPH] lchown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
1061 result = ceph_lchown(handle->data, smb_fname->base_name, uid, gid);
1062 DBG_DEBUG("[CEPH] lchown(...) = %d\n", result);
1063 WRAP_RETURN(result);
1066 static int cephwrap_chdir(struct vfs_handle_struct *handle,
1067 const struct smb_filename *smb_fname)
1069 int result = -1;
1070 DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, smb_fname->base_name);
1071 result = ceph_chdir(handle->data, smb_fname->base_name);
1072 DBG_DEBUG("[CEPH] chdir(...) = %d\n", result);
1073 WRAP_RETURN(result);
1076 static struct smb_filename *cephwrap_getwd(struct vfs_handle_struct *handle,
1077 TALLOC_CTX *ctx)
1079 const char *cwd = ceph_getcwd(handle->data);
1080 DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd);
1081 return synthetic_smb_fname(ctx,
1082 cwd,
1083 NULL,
1084 NULL,
1088 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1090 off_t space_to_write;
1091 uint64_t space_avail;
1092 uint64_t bsize,dfree,dsize;
1093 int ret;
1094 NTSTATUS status;
1095 SMB_STRUCT_STAT *pst;
1097 status = vfs_stat_fsp(fsp);
1098 if (!NT_STATUS_IS_OK(status)) {
1099 return -1;
1101 pst = &fsp->fsp_name->st;
1103 #ifdef S_ISFIFO
1104 if (S_ISFIFO(pst->st_ex_mode))
1105 return 0;
1106 #endif
1108 if (pst->st_ex_size == len)
1109 return 0;
1111 /* Shrink - just ftruncate. */
1112 if (pst->st_ex_size > len)
1113 return ftruncate(fsp->fh->fd, len);
1115 space_to_write = len - pst->st_ex_size;
1117 /* for allocation try fallocate first. This can fail on some
1118 platforms e.g. when the filesystem doesn't support it and no
1119 emulation is being done by the libc (like on AIX with JFS1). In that
1120 case we do our own emulation. fallocate implementations can
1121 return ENOTSUP or EINVAL in cases like that. */
1122 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
1123 if (ret == -1 && errno == ENOSPC) {
1124 return -1;
1126 if (ret == 0) {
1127 return 0;
1129 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
1130 "error %d. Falling back to slow manual allocation\n", errno));
1132 /* available disk space is enough or not? */
1133 space_avail =
1134 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
1135 /* space_avail is 1k blocks */
1136 if (space_avail == (uint64_t)-1 ||
1137 ((uint64_t)space_to_write/1024 > space_avail) ) {
1138 errno = ENOSPC;
1139 return -1;
1142 /* Write out the real space on disk. */
1143 return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
1146 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1148 int result = -1;
1149 SMB_STRUCT_STAT st;
1150 char c = 0;
1151 off_t currpos;
1153 DBG_DEBUG("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len));
1155 if (lp_strict_allocate(SNUM(fsp->conn))) {
1156 result = strict_allocate_ftruncate(handle, fsp, len);
1157 return result;
1160 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
1161 sys_ftruncate if the system supports it. Then I discovered that
1162 you can have some filesystems that support ftruncate
1163 expansion and some that don't! On Linux fat can't do
1164 ftruncate extend but ext2 can. */
1166 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1167 if (result == 0)
1168 goto done;
1170 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
1171 extend a file with ftruncate. Provide alternate implementation
1172 for this */
1173 currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
1174 if (currpos == -1) {
1175 goto done;
1178 /* Do an fstat to see if the file is longer than the requested
1179 size in which case the ftruncate above should have
1180 succeeded or shorter, in which case seek to len - 1 and
1181 write 1 byte of zero */
1182 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
1183 goto done;
1186 #ifdef S_ISFIFO
1187 if (S_ISFIFO(st.st_ex_mode)) {
1188 result = 0;
1189 goto done;
1191 #endif
1193 if (st.st_ex_size == len) {
1194 result = 0;
1195 goto done;
1198 if (st.st_ex_size > len) {
1199 /* the sys_ftruncate should have worked */
1200 goto done;
1203 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
1204 goto done;
1207 result = 0;
1209 done:
1211 return result;
1214 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
1216 DBG_DEBUG("[CEPH] lock\n");
1217 return true;
1220 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
1221 uint32_t share_mode, uint32_t access_mask)
1223 DBG_DEBUG("[CEPH] kernel_flock\n");
1225 * We must return zero here and pretend all is good.
1226 * One day we might have this in CEPH.
1228 return 0;
1231 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
1233 DBG_DEBUG("[CEPH] getlock returning false and errno=0\n");
1235 errno = 0;
1236 return false;
1240 * We cannot let this fall through to the default, because the file might only
1241 * be accessible from libceph (which is a user-space client) but the fd might
1242 * be for some file the kernel knows about.
1244 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
1245 int leasetype)
1247 int result = -1;
1249 DBG_DEBUG("[CEPH] linux_setlease\n");
1250 errno = ENOSYS;
1251 return result;
1254 static int cephwrap_symlink(struct vfs_handle_struct *handle,
1255 const char *link_target,
1256 const struct smb_filename *new_smb_fname)
1258 int result = -1;
1259 DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle,
1260 link_target,
1261 new_smb_fname->base_name);
1262 result = ceph_symlink(handle->data,
1263 link_target,
1264 new_smb_fname->base_name);
1265 DBG_DEBUG("[CEPH] symlink(...) = %d\n", result);
1266 WRAP_RETURN(result);
1269 static int cephwrap_readlink(struct vfs_handle_struct *handle,
1270 const struct smb_filename *smb_fname,
1271 char *buf,
1272 size_t bufsiz)
1274 int result = -1;
1275 DBG_DEBUG("[CEPH] readlink(%p, %s, %p, %llu)\n", handle,
1276 smb_fname->base_name, buf, llu(bufsiz));
1277 result = ceph_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1278 DBG_DEBUG("[CEPH] readlink(...) = %d\n", result);
1279 WRAP_RETURN(result);
1282 static int cephwrap_link(struct vfs_handle_struct *handle,
1283 const struct smb_filename *old_smb_fname,
1284 const struct smb_filename *new_smb_fname)
1286 int result = -1;
1287 DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle,
1288 old_smb_fname->base_name,
1289 new_smb_fname->base_name);
1290 result = ceph_link(handle->data,
1291 old_smb_fname->base_name,
1292 new_smb_fname->base_name);
1293 DBG_DEBUG("[CEPH] link(...) = %d\n", result);
1294 WRAP_RETURN(result);
1297 static int cephwrap_mknod(struct vfs_handle_struct *handle,
1298 const struct smb_filename *smb_fname,
1299 mode_t mode,
1300 SMB_DEV_T dev)
1302 int result = -1;
1303 DBG_DEBUG("[CEPH] mknod(%p, %s)\n", handle, smb_fname->base_name);
1304 result = ceph_mknod(handle->data, smb_fname->base_name, mode, dev);
1305 DBG_DEBUG("[CEPH] mknod(...) = %d\n", result);
1306 WRAP_RETURN(result);
1310 * This is a simple version of real-path ... a better version is needed to
1311 * ask libceph about symbolic links.
1313 static struct smb_filename *cephwrap_realpath(struct vfs_handle_struct *handle,
1314 TALLOC_CTX *ctx,
1315 const struct smb_filename *smb_fname)
1317 char *result = NULL;
1318 const char *path = smb_fname->base_name;
1319 size_t len = strlen(path);
1320 struct smb_filename *result_fname = NULL;
1321 int r = -1;
1323 if (len && (path[0] == '/')) {
1324 r = asprintf(&result, "%s", path);
1325 } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1326 if (len == 2) {
1327 r = asprintf(&result, "%s",
1328 handle->conn->connectpath);
1329 } else {
1330 r = asprintf(&result, "%s/%s",
1331 handle->conn->connectpath, &path[2]);
1333 } else {
1334 r = asprintf(&result, "%s/%s",
1335 handle->conn->connectpath, path);
1338 if (r < 0) {
1339 return NULL;
1342 DBG_DEBUG("[CEPH] realpath(%p, %s) = %s\n", handle, path, result);
1343 result_fname = synthetic_smb_fname(ctx,
1344 result,
1345 NULL,
1346 NULL,
1348 SAFE_FREE(result);
1349 return result_fname;
1352 static int cephwrap_chflags(struct vfs_handle_struct *handle,
1353 const struct smb_filename *smb_fname,
1354 unsigned int flags)
1356 errno = ENOSYS;
1357 return -1;
1360 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1361 const char *path,
1362 const char *name,
1363 TALLOC_CTX *mem_ctx,
1364 char **found_name)
1367 * Don't fall back to get_real_filename so callers can differentiate
1368 * between a full directory scan and an actual case-insensitive stat.
1370 errno = EOPNOTSUPP;
1371 return -1;
1374 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1375 const struct smb_filename *smb_fname)
1377 return handle->conn->connectpath;
1380 /****************************************************************
1381 Extended attribute operations.
1382 *****************************************************************/
1384 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,
1385 const struct smb_filename *smb_fname,
1386 const char *name,
1387 void *value,
1388 size_t size)
1390 int ret;
1391 DBG_DEBUG("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle,
1392 smb_fname->base_name, name, value, llu(size));
1393 ret = ceph_getxattr(handle->data,
1394 smb_fname->base_name, name, value, size);
1395 DBG_DEBUG("[CEPH] getxattr(...) = %d\n", ret);
1396 if (ret < 0) {
1397 WRAP_RETURN(ret);
1398 } else {
1399 return (ssize_t)ret;
1403 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1405 int ret;
1406 DBG_DEBUG("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size));
1407 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1408 ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1409 #else
1410 ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1411 #endif
1412 DBG_DEBUG("[CEPH] fgetxattr(...) = %d\n", ret);
1413 if (ret < 0) {
1414 WRAP_RETURN(ret);
1415 } else {
1416 return (ssize_t)ret;
1420 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle,
1421 const struct smb_filename *smb_fname,
1422 char *list,
1423 size_t size)
1425 int ret;
1426 DBG_DEBUG("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle,
1427 smb_fname->base_name, list, llu(size));
1428 ret = ceph_listxattr(handle->data, smb_fname->base_name, list, size);
1429 DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
1430 if (ret < 0) {
1431 WRAP_RETURN(ret);
1432 } else {
1433 return (ssize_t)ret;
1437 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1439 int ret;
1440 DBG_DEBUG("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size));
1441 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1442 ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1443 #else
1444 ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1445 #endif
1446 DBG_DEBUG("[CEPH] flistxattr(...) = %d\n", ret);
1447 if (ret < 0) {
1448 WRAP_RETURN(ret);
1449 } else {
1450 return (ssize_t)ret;
1454 static int cephwrap_removexattr(struct vfs_handle_struct *handle,
1455 const struct smb_filename *smb_fname,
1456 const char *name)
1458 int ret;
1459 DBG_DEBUG("[CEPH] removexattr(%p, %s, %s)\n", handle,
1460 smb_fname->base_name, name);
1461 ret = ceph_removexattr(handle->data, smb_fname->base_name, name);
1462 DBG_DEBUG("[CEPH] removexattr(...) = %d\n", ret);
1463 WRAP_RETURN(ret);
1466 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1468 int ret;
1469 DBG_DEBUG("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name);
1470 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1471 ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1472 #else
1473 ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1474 #endif
1475 DBG_DEBUG("[CEPH] fremovexattr(...) = %d\n", ret);
1476 WRAP_RETURN(ret);
1479 static int cephwrap_setxattr(struct vfs_handle_struct *handle,
1480 const struct smb_filename *smb_fname,
1481 const char *name,
1482 const void *value,
1483 size_t size,
1484 int flags)
1486 int ret;
1487 DBG_DEBUG("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle,
1488 smb_fname->base_name, name, value, llu(size), flags);
1489 ret = ceph_setxattr(handle->data, smb_fname->base_name,
1490 name, value, size, flags);
1491 DBG_DEBUG("[CEPH] setxattr(...) = %d\n", ret);
1492 WRAP_RETURN(ret);
1495 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1497 int ret;
1498 DBG_DEBUG("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags);
1499 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1500 ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1501 name, value, size, flags);
1502 #else
1503 ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1504 #endif
1505 DBG_DEBUG("[CEPH] fsetxattr(...) = %d\n", ret);
1506 WRAP_RETURN(ret);
1509 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1513 * We do not support AIO yet.
1516 DBG_DEBUG("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp);
1517 errno = ENOTSUP;
1518 return false;
1521 static struct vfs_fn_pointers ceph_fns = {
1522 /* Disk operations */
1524 .connect_fn = cephwrap_connect,
1525 .disconnect_fn = cephwrap_disconnect,
1526 .disk_free_fn = cephwrap_disk_free,
1527 .get_quota_fn = cephwrap_get_quota,
1528 .set_quota_fn = cephwrap_set_quota,
1529 .statvfs_fn = cephwrap_statvfs,
1530 .fs_capabilities_fn = cephwrap_fs_capabilities,
1532 /* Directory operations */
1534 .opendir_fn = cephwrap_opendir,
1535 .fdopendir_fn = cephwrap_fdopendir,
1536 .readdir_fn = cephwrap_readdir,
1537 .seekdir_fn = cephwrap_seekdir,
1538 .telldir_fn = cephwrap_telldir,
1539 .rewind_dir_fn = cephwrap_rewinddir,
1540 .mkdir_fn = cephwrap_mkdir,
1541 .rmdir_fn = cephwrap_rmdir,
1542 .closedir_fn = cephwrap_closedir,
1544 /* File operations */
1546 .open_fn = cephwrap_open,
1547 .close_fn = cephwrap_close,
1548 .pread_fn = cephwrap_pread,
1549 .pread_send_fn = cephwrap_pread_send,
1550 .pread_recv_fn = cephwrap_pread_recv,
1551 .pwrite_fn = cephwrap_pwrite,
1552 .pwrite_send_fn = cephwrap_pwrite_send,
1553 .pwrite_recv_fn = cephwrap_pwrite_recv,
1554 .lseek_fn = cephwrap_lseek,
1555 .sendfile_fn = cephwrap_sendfile,
1556 .recvfile_fn = cephwrap_recvfile,
1557 .rename_fn = cephwrap_rename,
1558 .fsync_send_fn = cephwrap_fsync_send,
1559 .fsync_recv_fn = cephwrap_fsync_recv,
1560 .stat_fn = cephwrap_stat,
1561 .fstat_fn = cephwrap_fstat,
1562 .lstat_fn = cephwrap_lstat,
1563 .unlink_fn = cephwrap_unlink,
1564 .chmod_fn = cephwrap_chmod,
1565 .fchmod_fn = cephwrap_fchmod,
1566 .chown_fn = cephwrap_chown,
1567 .fchown_fn = cephwrap_fchown,
1568 .lchown_fn = cephwrap_lchown,
1569 .chdir_fn = cephwrap_chdir,
1570 .getwd_fn = cephwrap_getwd,
1571 .ntimes_fn = cephwrap_ntimes,
1572 .ftruncate_fn = cephwrap_ftruncate,
1573 .lock_fn = cephwrap_lock,
1574 .kernel_flock_fn = cephwrap_kernel_flock,
1575 .linux_setlease_fn = cephwrap_linux_setlease,
1576 .getlock_fn = cephwrap_getlock,
1577 .symlink_fn = cephwrap_symlink,
1578 .readlink_fn = cephwrap_readlink,
1579 .link_fn = cephwrap_link,
1580 .mknod_fn = cephwrap_mknod,
1581 .realpath_fn = cephwrap_realpath,
1582 .chflags_fn = cephwrap_chflags,
1583 .get_real_filename_fn = cephwrap_get_real_filename,
1584 .connectpath_fn = cephwrap_connectpath,
1586 /* EA operations. */
1587 .getxattr_fn = cephwrap_getxattr,
1588 .fgetxattr_fn = cephwrap_fgetxattr,
1589 .listxattr_fn = cephwrap_listxattr,
1590 .flistxattr_fn = cephwrap_flistxattr,
1591 .removexattr_fn = cephwrap_removexattr,
1592 .fremovexattr_fn = cephwrap_fremovexattr,
1593 .setxattr_fn = cephwrap_setxattr,
1594 .fsetxattr_fn = cephwrap_fsetxattr,
1596 /* Posix ACL Operations */
1597 .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
1598 .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
1599 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1600 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1601 .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
1602 .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
1603 .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
1605 /* aio operations */
1606 .aio_force_fn = cephwrap_aio_force,
1609 static_decl_vfs;
1610 NTSTATUS vfs_ceph_init(TALLOC_CTX *ctx)
1612 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1613 "ceph", &ceph_fns);