s3: modules: vfs_ceph: Remove CHMOD_ACL in cephwrap_mkdir().
[Samba.git] / source3 / modules / vfs_ceph.c
blobf3b651b894e023493ab7d3c36f91da01a63888b8
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 char *parent = NULL;
372 const char *path = smb_fname->base_name;
374 DBG_DEBUG("[CEPH] mkdir(%p, %s)\n", handle, path);
376 if (lp_inherit_acls(SNUM(handle->conn))
377 && parent_dirname(talloc_tos(), path, &parent, NULL)
378 && directory_has_default_acl(handle->conn, parent)) {
379 mode = 0777;
382 TALLOC_FREE(parent);
384 result = ceph_mkdir(handle->data, path, mode);
385 return WRAP_RETURN(result);
388 static int cephwrap_rmdir(struct vfs_handle_struct *handle,
389 const struct smb_filename *smb_fname)
391 int result;
393 DBG_DEBUG("[CEPH] rmdir(%p, %s)\n", handle, smb_fname->base_name);
394 result = ceph_rmdir(handle->data, smb_fname->base_name);
395 DBG_DEBUG("[CEPH] rmdir(...) = %d\n", result);
396 WRAP_RETURN(result);
399 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
401 int result;
403 DBG_DEBUG("[CEPH] closedir(%p, %p)\n", handle, dirp);
404 result = ceph_closedir(handle->data, (struct ceph_dir_result *) dirp);
405 DBG_DEBUG("[CEPH] closedir(...) = %d\n", result);
406 WRAP_RETURN(result);
409 /* File operations */
411 static int cephwrap_open(struct vfs_handle_struct *handle,
412 struct smb_filename *smb_fname,
413 files_struct *fsp, int flags, mode_t mode)
415 int result = -ENOENT;
416 DBG_DEBUG("[CEPH] open(%p, %s, %p, %d, %d)\n", handle,
417 smb_fname_str_dbg(smb_fname), fsp, flags, mode);
419 if (smb_fname->stream_name) {
420 goto out;
423 result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
424 out:
425 DBG_DEBUG("[CEPH] open(...) = %d\n", result);
426 WRAP_RETURN(result);
429 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
431 int result;
433 DBG_DEBUG("[CEPH] close(%p, %p)\n", handle, fsp);
434 result = ceph_close(handle->data, fsp->fh->fd);
435 DBG_DEBUG("[CEPH] close(...) = %d\n", result);
437 WRAP_RETURN(result);
440 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
441 size_t n, off_t offset)
443 ssize_t result;
445 DBG_DEBUG("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
447 result = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
448 DBG_DEBUG("[CEPH] pread(...) = %llu\n", llu(result));
449 WRAP_RETURN(result);
452 struct cephwrap_pread_state {
453 ssize_t bytes_read;
454 struct vfs_aio_state vfs_aio_state;
458 * Fake up an async ceph read by calling the synchronous API.
460 static struct tevent_req *cephwrap_pread_send(struct vfs_handle_struct *handle,
461 TALLOC_CTX *mem_ctx,
462 struct tevent_context *ev,
463 struct files_struct *fsp,
464 void *data,
465 size_t n, off_t offset)
467 struct tevent_req *req = NULL;
468 struct cephwrap_pread_state *state = NULL;
469 int ret = -1;
471 DBG_DEBUG("[CEPH] %s\n", __func__);
472 req = tevent_req_create(mem_ctx, &state, struct cephwrap_pread_state);
473 if (req == NULL) {
474 return NULL;
477 ret = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
478 if (ret < 0) {
479 /* ceph returns -errno on error. */
480 tevent_req_error(req, -ret);
481 return tevent_req_post(req, ev);
484 state->bytes_read = ret;
485 tevent_req_done(req);
486 /* Return and schedule the completion of the call. */
487 return tevent_req_post(req, ev);
490 static ssize_t cephwrap_pread_recv(struct tevent_req *req,
491 struct vfs_aio_state *vfs_aio_state)
493 struct cephwrap_pread_state *state =
494 tevent_req_data(req, struct cephwrap_pread_state);
496 DBG_DEBUG("[CEPH] %s\n", __func__);
497 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
498 return -1;
500 *vfs_aio_state = state->vfs_aio_state;
501 return state->bytes_read;
504 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
505 size_t n, off_t offset)
507 ssize_t result;
509 DBG_DEBUG("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
510 result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
511 DBG_DEBUG("[CEPH] pwrite(...) = %llu\n", llu(result));
512 WRAP_RETURN(result);
515 struct cephwrap_pwrite_state {
516 ssize_t bytes_written;
517 struct vfs_aio_state vfs_aio_state;
521 * Fake up an async ceph write by calling the synchronous API.
523 static struct tevent_req *cephwrap_pwrite_send(struct vfs_handle_struct *handle,
524 TALLOC_CTX *mem_ctx,
525 struct tevent_context *ev,
526 struct files_struct *fsp,
527 const void *data,
528 size_t n, off_t offset)
530 struct tevent_req *req = NULL;
531 struct cephwrap_pwrite_state *state = NULL;
532 int ret = -1;
534 DBG_DEBUG("[CEPH] %s\n", __func__);
535 req = tevent_req_create(mem_ctx, &state, struct cephwrap_pwrite_state);
536 if (req == NULL) {
537 return NULL;
540 ret = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
541 if (ret < 0) {
542 /* ceph returns -errno on error. */
543 tevent_req_error(req, -ret);
544 return tevent_req_post(req, ev);
547 state->bytes_written = ret;
548 tevent_req_done(req);
549 /* Return and schedule the completion of the call. */
550 return tevent_req_post(req, ev);
553 static ssize_t cephwrap_pwrite_recv(struct tevent_req *req,
554 struct vfs_aio_state *vfs_aio_state)
556 struct cephwrap_pwrite_state *state =
557 tevent_req_data(req, struct cephwrap_pwrite_state);
559 DBG_DEBUG("[CEPH] %s\n", __func__);
560 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
561 return -1;
563 *vfs_aio_state = state->vfs_aio_state;
564 return state->bytes_written;
567 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
569 off_t result = 0;
571 DBG_DEBUG("[CEPH] cephwrap_lseek\n");
572 /* Cope with 'stat' file opens. */
573 if (fsp->fh->fd != -1) {
574 result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
576 WRAP_RETURN(result);
579 static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
580 off_t offset, size_t n)
583 * We cannot support sendfile because libceph is in user space.
585 DBG_DEBUG("[CEPH] cephwrap_sendfile\n");
586 errno = ENOTSUP;
587 return -1;
590 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
591 int fromfd,
592 files_struct *tofsp,
593 off_t offset,
594 size_t n)
597 * We cannot support recvfile because libceph is in user space.
599 DBG_DEBUG("[CEPH] cephwrap_recvfile\n");
600 errno=ENOTSUP;
601 return -1;
604 static int cephwrap_rename(struct vfs_handle_struct *handle,
605 const struct smb_filename *smb_fname_src,
606 const struct smb_filename *smb_fname_dst)
608 int result = -1;
609 DBG_DEBUG("[CEPH] cephwrap_rename\n");
610 if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
611 errno = ENOENT;
612 return result;
615 result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
616 WRAP_RETURN(result);
620 * Fake up an async ceph fsync by calling the synchronous API.
623 static struct tevent_req *cephwrap_fsync_send(struct vfs_handle_struct *handle,
624 TALLOC_CTX *mem_ctx,
625 struct tevent_context *ev,
626 files_struct *fsp)
628 struct tevent_req *req = NULL;
629 struct vfs_aio_state *state = NULL;
630 int ret = -1;
632 DBG_DEBUG("[CEPH] cephwrap_fsync_send\n");
634 req = tevent_req_create(mem_ctx, &state, struct vfs_aio_state);
635 if (req == NULL) {
636 return NULL;
639 /* Make sync call. */
640 ret = ceph_fsync(handle->data, fsp->fh->fd, false);
642 if (ret != 0) {
643 /* ceph_fsync returns -errno on error. */
644 tevent_req_error(req, -ret);
645 return tevent_req_post(req, ev);
648 /* Mark it as done. */
649 tevent_req_done(req);
650 /* Return and schedule the completion of the call. */
651 return tevent_req_post(req, ev);
654 static int cephwrap_fsync_recv(struct tevent_req *req,
655 struct vfs_aio_state *vfs_aio_state)
657 struct vfs_aio_state *state =
658 tevent_req_data(req, struct vfs_aio_state);
660 DBG_DEBUG("[CEPH] cephwrap_fsync_recv\n");
662 if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
663 return -1;
665 *vfs_aio_state = *state;
666 return 0;
669 #ifdef HAVE_CEPH_STATX
670 #define SAMBA_STATX_ATTR_MASK (CEPH_STATX_BASIC_STATS|CEPH_STATX_BTIME)
672 static void init_stat_ex_from_ceph_statx(struct stat_ex *dst, const struct ceph_statx *stx)
674 if ((stx->stx_mask & SAMBA_STATX_ATTR_MASK) != SAMBA_STATX_ATTR_MASK)
675 DBG_WARNING("%s: stx->stx_mask is incorrect (wanted %x, got %x)",
676 __func__, SAMBA_STATX_ATTR_MASK, stx->stx_mask);
678 dst->st_ex_dev = stx->stx_dev;
679 dst->st_ex_rdev = stx->stx_rdev;
680 dst->st_ex_ino = stx->stx_ino;
681 dst->st_ex_mode = stx->stx_mode;
682 dst->st_ex_uid = stx->stx_uid;
683 dst->st_ex_gid = stx->stx_gid;
684 dst->st_ex_size = stx->stx_size;
685 dst->st_ex_nlink = stx->stx_nlink;
686 dst->st_ex_atime = stx->stx_atime;
687 dst->st_ex_btime = stx->stx_btime;
688 dst->st_ex_ctime = stx->stx_ctime;
689 dst->st_ex_mtime = stx->stx_mtime;
690 dst->st_ex_calculated_birthtime = false;
691 dst->st_ex_blksize = stx->stx_blksize;
692 dst->st_ex_blocks = stx->stx_blocks;
695 static int cephwrap_stat(struct vfs_handle_struct *handle,
696 struct smb_filename *smb_fname)
698 int result = -1;
699 struct ceph_statx stx;
701 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
703 if (smb_fname->stream_name) {
704 errno = ENOENT;
705 return result;
708 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
709 SAMBA_STATX_ATTR_MASK, 0);
710 DBG_DEBUG("[CEPH] statx(...) = %d\n", result);
711 if (result < 0) {
712 WRAP_RETURN(result);
713 } else {
714 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
715 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
716 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
717 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
718 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
719 llu(stx.stx_size), llu(stx.stx_blksize),
720 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
721 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
723 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
724 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
725 return result;
728 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
730 int result = -1;
731 struct ceph_statx stx;
733 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
734 result = ceph_fstatx(handle->data, fsp->fh->fd, &stx,
735 SAMBA_STATX_ATTR_MASK, 0);
736 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
737 if (result < 0) {
738 WRAP_RETURN(result);
739 } else {
740 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
741 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
742 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
743 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
744 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
745 llu(stx.stx_size), llu(stx.stx_blksize),
746 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
747 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
749 init_stat_ex_from_ceph_statx(sbuf, &stx);
750 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
751 return result;
754 static int cephwrap_lstat(struct vfs_handle_struct *handle,
755 struct smb_filename *smb_fname)
757 int result = -1;
758 struct ceph_statx stx;
760 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
762 if (smb_fname->stream_name) {
763 errno = ENOENT;
764 return result;
767 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
768 SAMBA_STATX_ATTR_MASK, AT_SYMLINK_NOFOLLOW);
769 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
770 if (result < 0) {
771 WRAP_RETURN(result);
773 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
774 return result;
777 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
778 const struct smb_filename *smb_fname,
779 struct smb_file_time *ft)
781 struct ceph_statx stx = { 0 };
782 int result;
783 int mask = 0;
785 if (!null_timespec(ft->atime)) {
786 stx.stx_atime = ft->atime;
787 mask |= CEPH_SETATTR_ATIME;
789 if (!null_timespec(ft->mtime)) {
790 stx.stx_mtime = ft->mtime;
791 mask |= CEPH_SETATTR_MTIME;
793 if (!null_timespec(ft->create_time)) {
794 stx.stx_btime = ft->create_time;
795 mask |= CEPH_SETATTR_BTIME;
798 if (!mask) {
799 return 0;
802 result = ceph_setattrx(handle->data, smb_fname->base_name, &stx, mask, 0);
803 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
804 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
805 ft->create_time.tv_sec, result);
806 return result;
809 #else /* HAVE_CEPH_STATX */
811 static int cephwrap_stat(struct vfs_handle_struct *handle,
812 struct smb_filename *smb_fname)
814 int result = -1;
815 struct stat stbuf;
817 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
819 if (smb_fname->stream_name) {
820 errno = ENOENT;
821 return result;
824 result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
825 DBG_DEBUG("[CEPH] stat(...) = %d\n", result);
826 if (result < 0) {
827 WRAP_RETURN(result);
828 } else {
829 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
830 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
831 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
832 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
833 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
834 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
836 init_stat_ex_from_stat(
837 &smb_fname->st, &stbuf,
838 lp_fake_directory_create_times(SNUM(handle->conn)));
839 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
840 return result;
843 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
845 int result = -1;
846 struct stat stbuf;
848 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
849 result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
850 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
851 if (result < 0) {
852 WRAP_RETURN(result);
853 } else {
854 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
855 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
856 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
857 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
858 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
859 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
862 init_stat_ex_from_stat(
863 sbuf, &stbuf,
864 lp_fake_directory_create_times(SNUM(handle->conn)));
865 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
866 return result;
869 static int cephwrap_lstat(struct vfs_handle_struct *handle,
870 struct smb_filename *smb_fname)
872 int result = -1;
873 struct stat stbuf;
875 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
877 if (smb_fname->stream_name) {
878 errno = ENOENT;
879 return result;
882 result = ceph_lstat(handle->data, smb_fname->base_name, &stbuf);
883 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
884 if (result < 0) {
885 WRAP_RETURN(result);
887 init_stat_ex_from_stat(
888 &smb_fname->st, &stbuf,
889 lp_fake_directory_create_times(SNUM(handle->conn)));
890 return result;
893 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
894 const struct smb_filename *smb_fname,
895 struct smb_file_time *ft)
897 struct utimbuf buf;
898 int result;
900 if (null_timespec(ft->atime)) {
901 buf.actime = smb_fname->st.st_ex_atime.tv_sec;
902 } else {
903 buf.actime = ft->atime.tv_sec;
905 if (null_timespec(ft->mtime)) {
906 buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
907 } else {
908 buf.modtime = ft->mtime.tv_sec;
910 if (!null_timespec(ft->create_time)) {
911 set_create_timespec_ea(handle->conn, smb_fname,
912 ft->create_time);
914 if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
915 buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
916 return 0;
919 result = ceph_utime(handle->data, smb_fname->base_name, &buf);
920 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
921 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
922 ft->create_time.tv_sec, result);
923 return result;
925 #endif /* HAVE_CEPH_STATX */
927 static int cephwrap_unlink(struct vfs_handle_struct *handle,
928 const struct smb_filename *smb_fname)
930 int result = -1;
932 DBG_DEBUG("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
933 if (smb_fname->stream_name) {
934 errno = ENOENT;
935 return result;
937 result = ceph_unlink(handle->data, smb_fname->base_name);
938 DBG_DEBUG("[CEPH] unlink(...) = %d\n", result);
939 WRAP_RETURN(result);
942 static int cephwrap_chmod(struct vfs_handle_struct *handle,
943 const struct smb_filename *smb_fname,
944 mode_t mode)
946 int result;
948 DBG_DEBUG("[CEPH] chmod(%p, %s, %d)\n", handle, smb_fname->base_name, mode);
951 * We need to do this due to the fact that the default POSIX ACL
952 * chmod modifies the ACL *mask* for the group owner, not the
953 * group owner bits directly. JRA.
958 int saved_errno = errno; /* We might get ENOSYS */
959 result = SMB_VFS_CHMOD_ACL(handle->conn,
960 smb_fname,
961 mode);
962 if (result == 0) {
963 return result;
965 /* Error - return the old errno. */
966 errno = saved_errno;
969 result = ceph_chmod(handle->data, smb_fname->base_name, mode);
970 DBG_DEBUG("[CEPH] chmod(...) = %d\n", result);
971 WRAP_RETURN(result);
974 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
976 int result;
978 DBG_DEBUG("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode);
981 * We need to do this due to the fact that the default POSIX ACL
982 * chmod modifies the ACL *mask* for the group owner, not the
983 * group owner bits directly. JRA.
987 int saved_errno = errno; /* We might get ENOSYS */
988 if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
989 return result;
991 /* Error - return the old errno. */
992 errno = saved_errno;
995 #if defined(HAVE_FCHMOD)
996 result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
997 DBG_DEBUG("[CEPH] fchmod(...) = %d\n", result);
998 WRAP_RETURN(result);
999 #else
1000 errno = ENOSYS;
1001 #endif
1002 return -1;
1005 static int cephwrap_chown(struct vfs_handle_struct *handle,
1006 const struct smb_filename *smb_fname,
1007 uid_t uid,
1008 gid_t gid)
1010 int result;
1011 DBG_DEBUG("[CEPH] chown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
1012 result = ceph_chown(handle->data, smb_fname->base_name, uid, gid);
1013 DBG_DEBUG("[CEPH] chown(...) = %d\n", result);
1014 WRAP_RETURN(result);
1017 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
1019 int result;
1020 #ifdef HAVE_FCHOWN
1022 DBG_DEBUG("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid);
1023 result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
1024 DBG_DEBUG("[CEPH] fchown(...) = %d\n", result);
1025 WRAP_RETURN(result);
1026 #else
1027 errno = ENOSYS;
1028 result = -1;
1029 #endif
1030 return result;
1033 static int cephwrap_lchown(struct vfs_handle_struct *handle,
1034 const struct smb_filename *smb_fname,
1035 uid_t uid,
1036 gid_t gid)
1038 int result;
1039 DBG_DEBUG("[CEPH] lchown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
1040 result = ceph_lchown(handle->data, smb_fname->base_name, uid, gid);
1041 DBG_DEBUG("[CEPH] lchown(...) = %d\n", result);
1042 WRAP_RETURN(result);
1045 static int cephwrap_chdir(struct vfs_handle_struct *handle,
1046 const struct smb_filename *smb_fname)
1048 int result = -1;
1049 DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, smb_fname->base_name);
1050 result = ceph_chdir(handle->data, smb_fname->base_name);
1051 DBG_DEBUG("[CEPH] chdir(...) = %d\n", result);
1052 WRAP_RETURN(result);
1055 static struct smb_filename *cephwrap_getwd(struct vfs_handle_struct *handle,
1056 TALLOC_CTX *ctx)
1058 const char *cwd = ceph_getcwd(handle->data);
1059 DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd);
1060 return synthetic_smb_fname(ctx,
1061 cwd,
1062 NULL,
1063 NULL,
1067 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1069 off_t space_to_write;
1070 uint64_t space_avail;
1071 uint64_t bsize,dfree,dsize;
1072 int ret;
1073 NTSTATUS status;
1074 SMB_STRUCT_STAT *pst;
1076 status = vfs_stat_fsp(fsp);
1077 if (!NT_STATUS_IS_OK(status)) {
1078 return -1;
1080 pst = &fsp->fsp_name->st;
1082 #ifdef S_ISFIFO
1083 if (S_ISFIFO(pst->st_ex_mode))
1084 return 0;
1085 #endif
1087 if (pst->st_ex_size == len)
1088 return 0;
1090 /* Shrink - just ftruncate. */
1091 if (pst->st_ex_size > len)
1092 return ftruncate(fsp->fh->fd, len);
1094 space_to_write = len - pst->st_ex_size;
1096 /* for allocation try fallocate first. This can fail on some
1097 platforms e.g. when the filesystem doesn't support it and no
1098 emulation is being done by the libc (like on AIX with JFS1). In that
1099 case we do our own emulation. fallocate implementations can
1100 return ENOTSUP or EINVAL in cases like that. */
1101 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
1102 if (ret == -1 && errno == ENOSPC) {
1103 return -1;
1105 if (ret == 0) {
1106 return 0;
1108 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
1109 "error %d. Falling back to slow manual allocation\n", errno));
1111 /* available disk space is enough or not? */
1112 space_avail =
1113 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
1114 /* space_avail is 1k blocks */
1115 if (space_avail == (uint64_t)-1 ||
1116 ((uint64_t)space_to_write/1024 > space_avail) ) {
1117 errno = ENOSPC;
1118 return -1;
1121 /* Write out the real space on disk. */
1122 return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
1125 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1127 int result = -1;
1128 SMB_STRUCT_STAT st;
1129 char c = 0;
1130 off_t currpos;
1132 DBG_DEBUG("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len));
1134 if (lp_strict_allocate(SNUM(fsp->conn))) {
1135 result = strict_allocate_ftruncate(handle, fsp, len);
1136 return result;
1139 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
1140 sys_ftruncate if the system supports it. Then I discovered that
1141 you can have some filesystems that support ftruncate
1142 expansion and some that don't! On Linux fat can't do
1143 ftruncate extend but ext2 can. */
1145 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1146 if (result == 0)
1147 goto done;
1149 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
1150 extend a file with ftruncate. Provide alternate implementation
1151 for this */
1152 currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
1153 if (currpos == -1) {
1154 goto done;
1157 /* Do an fstat to see if the file is longer than the requested
1158 size in which case the ftruncate above should have
1159 succeeded or shorter, in which case seek to len - 1 and
1160 write 1 byte of zero */
1161 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
1162 goto done;
1165 #ifdef S_ISFIFO
1166 if (S_ISFIFO(st.st_ex_mode)) {
1167 result = 0;
1168 goto done;
1170 #endif
1172 if (st.st_ex_size == len) {
1173 result = 0;
1174 goto done;
1177 if (st.st_ex_size > len) {
1178 /* the sys_ftruncate should have worked */
1179 goto done;
1182 if (SMB_VFS_PWRITE(fsp, &c, 1, len-1)!=1) {
1183 goto done;
1186 result = 0;
1188 done:
1190 return result;
1193 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
1195 DBG_DEBUG("[CEPH] lock\n");
1196 return true;
1199 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
1200 uint32_t share_mode, uint32_t access_mask)
1202 DBG_DEBUG("[CEPH] kernel_flock\n");
1204 * We must return zero here and pretend all is good.
1205 * One day we might have this in CEPH.
1207 return 0;
1210 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
1212 DBG_DEBUG("[CEPH] getlock returning false and errno=0\n");
1214 errno = 0;
1215 return false;
1219 * We cannot let this fall through to the default, because the file might only
1220 * be accessible from libceph (which is a user-space client) but the fd might
1221 * be for some file the kernel knows about.
1223 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
1224 int leasetype)
1226 int result = -1;
1228 DBG_DEBUG("[CEPH] linux_setlease\n");
1229 errno = ENOSYS;
1230 return result;
1233 static int cephwrap_symlink(struct vfs_handle_struct *handle,
1234 const char *link_target,
1235 const struct smb_filename *new_smb_fname)
1237 int result = -1;
1238 DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle,
1239 link_target,
1240 new_smb_fname->base_name);
1241 result = ceph_symlink(handle->data,
1242 link_target,
1243 new_smb_fname->base_name);
1244 DBG_DEBUG("[CEPH] symlink(...) = %d\n", result);
1245 WRAP_RETURN(result);
1248 static int cephwrap_readlink(struct vfs_handle_struct *handle,
1249 const struct smb_filename *smb_fname,
1250 char *buf,
1251 size_t bufsiz)
1253 int result = -1;
1254 DBG_DEBUG("[CEPH] readlink(%p, %s, %p, %llu)\n", handle,
1255 smb_fname->base_name, buf, llu(bufsiz));
1256 result = ceph_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
1257 DBG_DEBUG("[CEPH] readlink(...) = %d\n", result);
1258 WRAP_RETURN(result);
1261 static int cephwrap_link(struct vfs_handle_struct *handle,
1262 const struct smb_filename *old_smb_fname,
1263 const struct smb_filename *new_smb_fname)
1265 int result = -1;
1266 DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle,
1267 old_smb_fname->base_name,
1268 new_smb_fname->base_name);
1269 result = ceph_link(handle->data,
1270 old_smb_fname->base_name,
1271 new_smb_fname->base_name);
1272 DBG_DEBUG("[CEPH] link(...) = %d\n", result);
1273 WRAP_RETURN(result);
1276 static int cephwrap_mknod(struct vfs_handle_struct *handle,
1277 const struct smb_filename *smb_fname,
1278 mode_t mode,
1279 SMB_DEV_T dev)
1281 int result = -1;
1282 DBG_DEBUG("[CEPH] mknod(%p, %s)\n", handle, smb_fname->base_name);
1283 result = ceph_mknod(handle->data, smb_fname->base_name, mode, dev);
1284 DBG_DEBUG("[CEPH] mknod(...) = %d\n", result);
1285 WRAP_RETURN(result);
1289 * This is a simple version of real-path ... a better version is needed to
1290 * ask libceph about symbolic links.
1292 static struct smb_filename *cephwrap_realpath(struct vfs_handle_struct *handle,
1293 TALLOC_CTX *ctx,
1294 const struct smb_filename *smb_fname)
1296 char *result = NULL;
1297 const char *path = smb_fname->base_name;
1298 size_t len = strlen(path);
1299 struct smb_filename *result_fname = NULL;
1300 int r = -1;
1302 if (len && (path[0] == '/')) {
1303 r = asprintf(&result, "%s", path);
1304 } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1305 if (len == 2) {
1306 r = asprintf(&result, "%s",
1307 handle->conn->connectpath);
1308 } else {
1309 r = asprintf(&result, "%s/%s",
1310 handle->conn->connectpath, &path[2]);
1312 } else {
1313 r = asprintf(&result, "%s/%s",
1314 handle->conn->connectpath, path);
1317 if (r < 0) {
1318 return NULL;
1321 DBG_DEBUG("[CEPH] realpath(%p, %s) = %s\n", handle, path, result);
1322 result_fname = synthetic_smb_fname(ctx,
1323 result,
1324 NULL,
1325 NULL,
1327 SAFE_FREE(result);
1328 return result_fname;
1331 static int cephwrap_chflags(struct vfs_handle_struct *handle,
1332 const struct smb_filename *smb_fname,
1333 unsigned int flags)
1335 errno = ENOSYS;
1336 return -1;
1339 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1340 const char *path,
1341 const char *name,
1342 TALLOC_CTX *mem_ctx,
1343 char **found_name)
1346 * Don't fall back to get_real_filename so callers can differentiate
1347 * between a full directory scan and an actual case-insensitive stat.
1349 errno = EOPNOTSUPP;
1350 return -1;
1353 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1354 const struct smb_filename *smb_fname)
1356 return handle->conn->connectpath;
1359 /****************************************************************
1360 Extended attribute operations.
1361 *****************************************************************/
1363 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,
1364 const struct smb_filename *smb_fname,
1365 const char *name,
1366 void *value,
1367 size_t size)
1369 int ret;
1370 DBG_DEBUG("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle,
1371 smb_fname->base_name, name, value, llu(size));
1372 ret = ceph_getxattr(handle->data,
1373 smb_fname->base_name, name, value, size);
1374 DBG_DEBUG("[CEPH] getxattr(...) = %d\n", ret);
1375 if (ret < 0) {
1376 WRAP_RETURN(ret);
1377 } else {
1378 return (ssize_t)ret;
1382 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1384 int ret;
1385 DBG_DEBUG("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size));
1386 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1387 ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1388 #else
1389 ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1390 #endif
1391 DBG_DEBUG("[CEPH] fgetxattr(...) = %d\n", ret);
1392 if (ret < 0) {
1393 WRAP_RETURN(ret);
1394 } else {
1395 return (ssize_t)ret;
1399 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle,
1400 const struct smb_filename *smb_fname,
1401 char *list,
1402 size_t size)
1404 int ret;
1405 DBG_DEBUG("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle,
1406 smb_fname->base_name, list, llu(size));
1407 ret = ceph_listxattr(handle->data, smb_fname->base_name, list, size);
1408 DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
1409 if (ret < 0) {
1410 WRAP_RETURN(ret);
1411 } else {
1412 return (ssize_t)ret;
1416 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1418 int ret;
1419 DBG_DEBUG("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size));
1420 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1421 ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1422 #else
1423 ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1424 #endif
1425 DBG_DEBUG("[CEPH] flistxattr(...) = %d\n", ret);
1426 if (ret < 0) {
1427 WRAP_RETURN(ret);
1428 } else {
1429 return (ssize_t)ret;
1433 static int cephwrap_removexattr(struct vfs_handle_struct *handle,
1434 const struct smb_filename *smb_fname,
1435 const char *name)
1437 int ret;
1438 DBG_DEBUG("[CEPH] removexattr(%p, %s, %s)\n", handle,
1439 smb_fname->base_name, name);
1440 ret = ceph_removexattr(handle->data, smb_fname->base_name, name);
1441 DBG_DEBUG("[CEPH] removexattr(...) = %d\n", ret);
1442 WRAP_RETURN(ret);
1445 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1447 int ret;
1448 DBG_DEBUG("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name);
1449 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1450 ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1451 #else
1452 ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1453 #endif
1454 DBG_DEBUG("[CEPH] fremovexattr(...) = %d\n", ret);
1455 WRAP_RETURN(ret);
1458 static int cephwrap_setxattr(struct vfs_handle_struct *handle,
1459 const struct smb_filename *smb_fname,
1460 const char *name,
1461 const void *value,
1462 size_t size,
1463 int flags)
1465 int ret;
1466 DBG_DEBUG("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle,
1467 smb_fname->base_name, name, value, llu(size), flags);
1468 ret = ceph_setxattr(handle->data, smb_fname->base_name,
1469 name, value, size, flags);
1470 DBG_DEBUG("[CEPH] setxattr(...) = %d\n", ret);
1471 WRAP_RETURN(ret);
1474 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1476 int ret;
1477 DBG_DEBUG("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags);
1478 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1479 ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1480 name, value, size, flags);
1481 #else
1482 ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1483 #endif
1484 DBG_DEBUG("[CEPH] fsetxattr(...) = %d\n", ret);
1485 WRAP_RETURN(ret);
1488 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1492 * We do not support AIO yet.
1495 DBG_DEBUG("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp);
1496 errno = ENOTSUP;
1497 return false;
1500 static struct vfs_fn_pointers ceph_fns = {
1501 /* Disk operations */
1503 .connect_fn = cephwrap_connect,
1504 .disconnect_fn = cephwrap_disconnect,
1505 .disk_free_fn = cephwrap_disk_free,
1506 .get_quota_fn = cephwrap_get_quota,
1507 .set_quota_fn = cephwrap_set_quota,
1508 .statvfs_fn = cephwrap_statvfs,
1509 .fs_capabilities_fn = cephwrap_fs_capabilities,
1511 /* Directory operations */
1513 .opendir_fn = cephwrap_opendir,
1514 .fdopendir_fn = cephwrap_fdopendir,
1515 .readdir_fn = cephwrap_readdir,
1516 .seekdir_fn = cephwrap_seekdir,
1517 .telldir_fn = cephwrap_telldir,
1518 .rewind_dir_fn = cephwrap_rewinddir,
1519 .mkdir_fn = cephwrap_mkdir,
1520 .rmdir_fn = cephwrap_rmdir,
1521 .closedir_fn = cephwrap_closedir,
1523 /* File operations */
1525 .open_fn = cephwrap_open,
1526 .close_fn = cephwrap_close,
1527 .pread_fn = cephwrap_pread,
1528 .pread_send_fn = cephwrap_pread_send,
1529 .pread_recv_fn = cephwrap_pread_recv,
1530 .pwrite_fn = cephwrap_pwrite,
1531 .pwrite_send_fn = cephwrap_pwrite_send,
1532 .pwrite_recv_fn = cephwrap_pwrite_recv,
1533 .lseek_fn = cephwrap_lseek,
1534 .sendfile_fn = cephwrap_sendfile,
1535 .recvfile_fn = cephwrap_recvfile,
1536 .rename_fn = cephwrap_rename,
1537 .fsync_send_fn = cephwrap_fsync_send,
1538 .fsync_recv_fn = cephwrap_fsync_recv,
1539 .stat_fn = cephwrap_stat,
1540 .fstat_fn = cephwrap_fstat,
1541 .lstat_fn = cephwrap_lstat,
1542 .unlink_fn = cephwrap_unlink,
1543 .chmod_fn = cephwrap_chmod,
1544 .fchmod_fn = cephwrap_fchmod,
1545 .chown_fn = cephwrap_chown,
1546 .fchown_fn = cephwrap_fchown,
1547 .lchown_fn = cephwrap_lchown,
1548 .chdir_fn = cephwrap_chdir,
1549 .getwd_fn = cephwrap_getwd,
1550 .ntimes_fn = cephwrap_ntimes,
1551 .ftruncate_fn = cephwrap_ftruncate,
1552 .lock_fn = cephwrap_lock,
1553 .kernel_flock_fn = cephwrap_kernel_flock,
1554 .linux_setlease_fn = cephwrap_linux_setlease,
1555 .getlock_fn = cephwrap_getlock,
1556 .symlink_fn = cephwrap_symlink,
1557 .readlink_fn = cephwrap_readlink,
1558 .link_fn = cephwrap_link,
1559 .mknod_fn = cephwrap_mknod,
1560 .realpath_fn = cephwrap_realpath,
1561 .chflags_fn = cephwrap_chflags,
1562 .get_real_filename_fn = cephwrap_get_real_filename,
1563 .connectpath_fn = cephwrap_connectpath,
1565 /* EA operations. */
1566 .getxattr_fn = cephwrap_getxattr,
1567 .fgetxattr_fn = cephwrap_fgetxattr,
1568 .listxattr_fn = cephwrap_listxattr,
1569 .flistxattr_fn = cephwrap_flistxattr,
1570 .removexattr_fn = cephwrap_removexattr,
1571 .fremovexattr_fn = cephwrap_fremovexattr,
1572 .setxattr_fn = cephwrap_setxattr,
1573 .fsetxattr_fn = cephwrap_fsetxattr,
1575 /* Posix ACL Operations */
1576 .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
1577 .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
1578 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1579 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1580 .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
1581 .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
1582 .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
1584 /* aio operations */
1585 .aio_force_fn = cephwrap_aio_force,
1588 static_decl_vfs;
1589 NTSTATUS vfs_ceph_init(TALLOC_CTX *ctx)
1591 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1592 "ceph", &ceph_fns);