vfs_ceph: replace deprecated ceph_shutdown() call
[Samba.git] / source3 / modules / vfs_ceph.c
blob5cdb37236736c4309c5b892c451def0d0180316a
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"
41 #undef DBGC_CLASS
42 #define DBGC_CLASS DBGC_VFS
44 #ifndef LIBCEPHFS_VERSION
45 #define LIBCEPHFS_VERSION(maj, min, extra) ((maj << 16) + (min << 8) + extra)
46 #define LIBCEPHFS_VERSION_CODE LIBCEPHFS_VERSION(0, 0, 0)
47 #endif
50 * Use %llu whenever we have a 64bit unsigned int, and cast to (long long unsigned)
52 #define llu(_var) ((long long unsigned)_var)
55 * Note, libceph's return code model is to return -errno! So we have to convert
56 * to what Samba expects, with is set errno to -return and return -1
58 #define WRAP_RETURN(_res) \
59 errno = 0; \
60 if (_res < 0) { \
61 errno = -_res; \
62 return -1; \
63 } \
64 return _res \
67 * We mount only one file system and then all shares are assumed to be in that.
68 * FIXME: If we want to support more than one FS, then we have to deal with
69 * this differently.
71 * So, cmount tells us if we have been this way before and whether
72 * we need to mount ceph and cmount_cnt tells us how many times we have
73 * connected
75 static struct ceph_mount_info * cmount = NULL;
76 static uint32_t cmount_cnt = 0;
78 /* Check for NULL pointer parameters in cephwrap_* functions */
80 /* We don't want to have NULL function pointers lying around. Someone
81 is sure to try and execute them. These stubs are used to prevent
82 this possibility. */
84 static int cephwrap_connect(struct vfs_handle_struct *handle, const char *service, const char *user)
86 int ret;
87 char buf[256];
89 const char * conf_file;
91 if (cmount) {
92 handle->data = cmount; /* We have been here before */
93 cmount_cnt++;
94 return 0;
97 conf_file = lp_parm_const_string(SNUM(handle->conn), "ceph", "config_file", NULL);
99 DBG_DEBUG( "[CEPH] calling: ceph_create\n" );
100 ret = ceph_create(&cmount, NULL);
101 if (ret)
102 goto err_out;
104 if (conf_file) {
105 /* Override the config file */
106 DBG_DEBUG( "[CEPH] calling: ceph_conf_read_file\n" );
107 ret = ceph_conf_read_file(cmount, conf_file);
108 } else {
110 DBG_DEBUG( "[CEPH] calling: ceph_conf_read_file with %s\n", conf_file);
111 ret = ceph_conf_read_file(cmount, NULL);
114 if (ret) {
115 goto err_cm_release;
118 DBG_DEBUG( "[CEPH] calling: ceph_conf_get\n" );
119 ret = ceph_conf_get(cmount, "log file", buf, sizeof(buf));
120 if (ret < 0) {
121 goto err_cm_release;
124 DBG_DEBUG("[CEPH] calling: ceph_mount\n");
125 ret = ceph_mount(cmount, NULL);
126 if (ret < 0) {
127 goto err_cm_release;
131 * encode mount context/state into our vfs/connection holding structure
132 * cmount is a ceph_mount_t*
134 handle->data = cmount;
135 cmount_cnt++;
137 return 0;
139 err_cm_release:
140 ceph_release(cmount);
141 cmount = NULL;
142 err_out:
144 * Handle the error correctly. Ceph returns -errno.
146 DBG_DEBUG("[CEPH] Error return: %s\n", strerror(-ret));
147 WRAP_RETURN(ret);
150 static void cephwrap_disconnect(struct vfs_handle_struct *handle)
152 int ret;
154 if (!cmount) {
155 DBG_ERR("[CEPH] Error, ceph not mounted\n");
156 return;
159 /* Should we unmount/shutdown? Only if the last disconnect? */
160 if (--cmount_cnt) {
161 DBG_DEBUG("[CEPH] Not shuting down CEPH because still more connections\n");
162 return;
165 ret = ceph_unmount(cmount);
166 if (ret < 0) {
167 DBG_ERR("[CEPH] failed to unmount: %s\n", strerror(-ret));
170 ret = ceph_release(cmount);
171 if (ret < 0) {
172 DBG_ERR("[CEPH] failed to release: %s\n", strerror(-ret));
175 cmount = NULL; /* Make it safe */
178 /* Disk operations */
180 static uint64_t cephwrap_disk_free(struct vfs_handle_struct *handle,
181 const char *path, uint64_t *bsize,
182 uint64_t *dfree, uint64_t *dsize)
184 struct statvfs statvfs_buf;
185 int ret;
187 if (!(ret = ceph_statfs(handle->data, path, &statvfs_buf))) {
189 * Provide all the correct values.
191 *bsize = statvfs_buf.f_bsize;
192 *dfree = statvfs_buf.f_bavail;
193 *dsize = statvfs_buf.f_blocks;
194 DBG_DEBUG("[CEPH] bsize: %llu, dfree: %llu, dsize: %llu\n",
195 llu(*bsize), llu(*dfree), llu(*dsize));
196 return *dfree;
197 } else {
198 DBG_DEBUG("[CEPH] ceph_statfs returned %d\n", ret);
199 WRAP_RETURN(ret);
203 static int cephwrap_get_quota(struct vfs_handle_struct *handle,
204 const char *path, enum SMB_QUOTA_TYPE qtype,
205 unid_t id, SMB_DISK_QUOTA *qt)
207 /* libceph: Ceph does not implement this */
208 #if 0
209 /* was ifdef HAVE_SYS_QUOTAS */
210 int ret;
212 ret = ceph_get_quota(handle->conn->connectpath, qtype, id, qt);
214 if (ret) {
215 errno = -ret;
216 ret = -1;
219 return ret;
220 #else
221 errno = ENOSYS;
222 return -1;
223 #endif
226 static int cephwrap_set_quota(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
228 /* libceph: Ceph does not implement this */
229 #if 0
230 /* was ifdef HAVE_SYS_QUOTAS */
231 int ret;
233 ret = ceph_set_quota(handle->conn->connectpath, qtype, id, qt);
234 if (ret) {
235 errno = -ret;
236 ret = -1;
239 return ret;
240 #else
241 WRAP_RETURN(-ENOSYS);
242 #endif
245 static int cephwrap_statvfs(struct vfs_handle_struct *handle, const char *path, vfs_statvfs_struct *statbuf)
247 struct statvfs statvfs_buf;
248 int ret;
250 ret = ceph_statfs(handle->data, path, &statvfs_buf);
251 if (ret < 0) {
252 WRAP_RETURN(ret);
253 } else {
254 statbuf->OptimalTransferSize = statvfs_buf.f_frsize;
255 statbuf->BlockSize = statvfs_buf.f_bsize;
256 statbuf->TotalBlocks = statvfs_buf.f_blocks;
257 statbuf->BlocksAvail = statvfs_buf.f_bfree;
258 statbuf->UserBlocksAvail = statvfs_buf.f_bavail;
259 statbuf->TotalFileNodes = statvfs_buf.f_files;
260 statbuf->FreeFileNodes = statvfs_buf.f_ffree;
261 statbuf->FsIdentifier = statvfs_buf.f_fsid;
262 DBG_DEBUG("[CEPH] f_bsize: %ld, f_blocks: %ld, f_bfree: %ld, f_bavail: %ld\n",
263 (long int)statvfs_buf.f_bsize, (long int)statvfs_buf.f_blocks,
264 (long int)statvfs_buf.f_bfree, (long int)statvfs_buf.f_bavail);
266 return ret;
269 /* Directory operations */
271 static DIR *cephwrap_opendir(struct vfs_handle_struct *handle,
272 const struct smb_filename *smb_fname,
273 const char *mask, uint32_t attr)
275 int ret = 0;
276 struct ceph_dir_result *result;
277 DBG_DEBUG("[CEPH] opendir(%p, %s)\n", handle, smb_fname->base_name);
279 /* Returns NULL if it does not exist or there are problems ? */
280 ret = ceph_opendir(handle->data, smb_fname->base_name, &result);
281 if (ret < 0) {
282 result = NULL;
283 errno = -ret; /* We return result which is NULL in this case */
286 DBG_DEBUG("[CEPH] opendir(...) = %d\n", ret);
287 return (DIR *) result;
290 static DIR *cephwrap_fdopendir(struct vfs_handle_struct *handle,
291 struct files_struct *fsp,
292 const char *mask,
293 uint32_t attributes)
295 int ret = 0;
296 struct ceph_dir_result *result;
297 DBG_DEBUG("[CEPH] fdopendir(%p, %p)\n", handle, fsp);
299 ret = ceph_opendir(handle->data, fsp->fsp_name->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] fdopendir(...) = %d\n", ret);
306 return (DIR *) result;
309 static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
310 DIR *dirp,
311 SMB_STRUCT_STAT *sbuf)
313 struct dirent *result;
315 DBG_DEBUG("[CEPH] readdir(%p, %p)\n", handle, dirp);
316 result = ceph_readdir(handle->data, (struct ceph_dir_result *) dirp);
317 DBG_DEBUG("[CEPH] readdir(...) = %p\n", result);
319 /* Default Posix readdir() does not give us stat info.
320 * Set to invalid to indicate we didn't return this info. */
321 if (sbuf)
322 SET_STAT_INVALID(*sbuf);
323 return result;
326 static void cephwrap_seekdir(struct vfs_handle_struct *handle, DIR *dirp, long offset)
328 DBG_DEBUG("[CEPH] seekdir(%p, %p, %ld)\n", handle, dirp, offset);
329 ceph_seekdir(handle->data, (struct ceph_dir_result *) dirp, offset);
332 static long cephwrap_telldir(struct vfs_handle_struct *handle, DIR *dirp)
334 long ret;
335 DBG_DEBUG("[CEPH] telldir(%p, %p)\n", handle, dirp);
336 ret = ceph_telldir(handle->data, (struct ceph_dir_result *) dirp);
337 DBG_DEBUG("[CEPH] telldir(...) = %ld\n", ret);
338 WRAP_RETURN(ret);
341 static void cephwrap_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
343 DBG_DEBUG("[CEPH] rewinddir(%p, %p)\n", handle, dirp);
344 ceph_rewinddir(handle->data, (struct ceph_dir_result *) dirp);
347 static int cephwrap_mkdir(struct vfs_handle_struct *handle,
348 const struct smb_filename *smb_fname,
349 mode_t mode)
351 int result;
352 bool has_dacl = False;
353 char *parent = NULL;
354 const char *path = smb_fname->base_name;
356 DBG_DEBUG("[CEPH] mkdir(%p, %s)\n", handle, path);
358 if (lp_inherit_acls(SNUM(handle->conn))
359 && parent_dirname(talloc_tos(), path, &parent, NULL)
360 && (has_dacl = directory_has_default_acl(handle->conn, parent)))
361 mode = 0777;
363 TALLOC_FREE(parent);
365 result = ceph_mkdir(handle->data, path, mode);
368 * Note. This order is important
370 if (result) {
371 WRAP_RETURN(result);
372 } else if (result == 0 && !has_dacl) {
374 * We need to do this as the default behavior of POSIX ACLs
375 * is to set the mask to be the requested group permission
376 * bits, not the group permission bits to be the requested
377 * group permission bits. This is not what we want, as it will
378 * mess up any inherited ACL bits that were set. JRA.
380 int saved_errno = errno; /* We may get ENOSYS */
381 if ((SMB_VFS_CHMOD_ACL(handle->conn, smb_fname, mode) == -1) &&
382 (errno == ENOSYS)) {
383 errno = saved_errno;
387 return result;
390 static int cephwrap_rmdir(struct vfs_handle_struct *handle,
391 const struct smb_filename *smb_fname)
393 int result;
395 DBG_DEBUG("[CEPH] rmdir(%p, %s)\n", handle, smb_fname->base_name);
396 result = ceph_rmdir(handle->data, smb_fname->base_name);
397 DBG_DEBUG("[CEPH] rmdir(...) = %d\n", result);
398 WRAP_RETURN(result);
401 static int cephwrap_closedir(struct vfs_handle_struct *handle, DIR *dirp)
403 int result;
405 DBG_DEBUG("[CEPH] closedir(%p, %p)\n", handle, dirp);
406 result = ceph_closedir(handle->data, (struct ceph_dir_result *) dirp);
407 DBG_DEBUG("[CEPH] closedir(...) = %d\n", result);
408 WRAP_RETURN(result);
411 /* File operations */
413 static int cephwrap_open(struct vfs_handle_struct *handle,
414 struct smb_filename *smb_fname,
415 files_struct *fsp, int flags, mode_t mode)
417 int result = -ENOENT;
418 DBG_DEBUG("[CEPH] open(%p, %s, %p, %d, %d)\n", handle,
419 smb_fname_str_dbg(smb_fname), fsp, flags, mode);
421 if (smb_fname->stream_name) {
422 goto out;
425 result = ceph_open(handle->data, smb_fname->base_name, flags, mode);
426 out:
427 DBG_DEBUG("[CEPH] open(...) = %d\n", result);
428 WRAP_RETURN(result);
431 static int cephwrap_close(struct vfs_handle_struct *handle, files_struct *fsp)
433 int result;
435 DBG_DEBUG("[CEPH] close(%p, %p)\n", handle, fsp);
436 result = ceph_close(handle->data, fsp->fh->fd);
437 DBG_DEBUG("[CEPH] close(...) = %d\n", result);
439 WRAP_RETURN(result);
442 static ssize_t cephwrap_read(struct vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n)
444 ssize_t result;
446 DBG_DEBUG("[CEPH] read(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
448 /* Using -1 for the offset means read/write rather than pread/pwrite */
449 result = ceph_read(handle->data, fsp->fh->fd, data, n, -1);
450 DBG_DEBUG("[CEPH] read(...) = %llu\n", llu(result));
451 WRAP_RETURN(result);
454 static ssize_t cephwrap_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data,
455 size_t n, off_t offset)
457 ssize_t result;
459 DBG_DEBUG("[CEPH] pread(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
461 result = ceph_read(handle->data, fsp->fh->fd, data, n, offset);
462 DBG_DEBUG("[CEPH] pread(...) = %llu\n", llu(result));
463 WRAP_RETURN(result);
467 static ssize_t cephwrap_write(struct vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n)
469 ssize_t result;
471 DBG_DEBUG("[CEPH] write(%p, %p, %p, %llu)\n", handle, fsp, data, llu(n));
473 result = ceph_write(handle->data, fsp->fh->fd, data, n, -1);
475 DBG_DEBUG("[CEPH] write(...) = %llu\n", llu(result));
476 if (result < 0) {
477 WRAP_RETURN(result);
479 fsp->fh->pos += result;
480 return result;
483 static ssize_t cephwrap_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data,
484 size_t n, off_t offset)
486 ssize_t result;
488 DBG_DEBUG("[CEPH] pwrite(%p, %p, %p, %llu, %llu)\n", handle, fsp, data, llu(n), llu(offset));
489 result = ceph_write(handle->data, fsp->fh->fd, data, n, offset);
490 DBG_DEBUG("[CEPH] pwrite(...) = %llu\n", llu(result));
491 WRAP_RETURN(result);
494 static off_t cephwrap_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence)
496 off_t result = 0;
498 DBG_DEBUG("[CEPH] cephwrap_lseek\n");
499 /* Cope with 'stat' file opens. */
500 if (fsp->fh->fd != -1) {
501 result = ceph_lseek(handle->data, fsp->fh->fd, offset, whence);
503 WRAP_RETURN(result);
506 static ssize_t cephwrap_sendfile(struct vfs_handle_struct *handle, int tofd, files_struct *fromfsp, const DATA_BLOB *hdr,
507 off_t offset, size_t n)
510 * We cannot support sendfile because libceph is in user space.
512 DBG_DEBUG("[CEPH] cephwrap_sendfile\n");
513 errno = ENOTSUP;
514 return -1;
517 static ssize_t cephwrap_recvfile(struct vfs_handle_struct *handle,
518 int fromfd,
519 files_struct *tofsp,
520 off_t offset,
521 size_t n)
524 * We cannot support recvfile because libceph is in user space.
526 DBG_DEBUG("[CEPH] cephwrap_recvfile\n");
527 errno=ENOTSUP;
528 return -1;
531 static int cephwrap_rename(struct vfs_handle_struct *handle,
532 const struct smb_filename *smb_fname_src,
533 const struct smb_filename *smb_fname_dst)
535 int result = -1;
536 DBG_DEBUG("[CEPH] cephwrap_rename\n");
537 if (smb_fname_src->stream_name || smb_fname_dst->stream_name) {
538 errno = ENOENT;
539 return result;
542 result = ceph_rename(handle->data, smb_fname_src->base_name, smb_fname_dst->base_name);
543 WRAP_RETURN(result);
546 static int cephwrap_fsync(struct vfs_handle_struct *handle, files_struct *fsp)
548 int result;
549 DBG_DEBUG("[CEPH] cephwrap_fsync\n");
550 result = ceph_fsync(handle->data, fsp->fh->fd, false);
551 WRAP_RETURN(result);
554 #ifdef HAVE_CEPH_STATX
555 #define SAMBA_STATX_ATTR_MASK (CEPH_STATX_BASIC_STATS|CEPH_STATX_BTIME)
557 static void init_stat_ex_from_ceph_statx(struct stat_ex *dst, const struct ceph_statx *stx)
559 if ((stx->stx_mask & SAMBA_STATX_ATTR_MASK) != SAMBA_STATX_ATTR_MASK)
560 DBG_WARNING("%s: stx->stx_mask is incorrect (wanted %x, got %x)",
561 __func__, SAMBA_STATX_ATTR_MASK, stx->stx_mask);
563 dst->st_ex_dev = stx->stx_dev;
564 dst->st_ex_rdev = stx->stx_rdev;
565 dst->st_ex_ino = stx->stx_ino;
566 dst->st_ex_mode = stx->stx_mode;
567 dst->st_ex_uid = stx->stx_uid;
568 dst->st_ex_gid = stx->stx_gid;
569 dst->st_ex_size = stx->stx_size;
570 dst->st_ex_nlink = stx->stx_nlink;
571 dst->st_ex_atime = stx->stx_atime;
572 dst->st_ex_btime = stx->stx_btime;
573 dst->st_ex_ctime = stx->stx_ctime;
574 dst->st_ex_mtime = stx->stx_mtime;
575 dst->st_ex_calculated_birthtime = false;
576 dst->st_ex_blksize = stx->stx_blksize;
577 dst->st_ex_blocks = stx->stx_blocks;
580 static int cephwrap_stat(struct vfs_handle_struct *handle,
581 struct smb_filename *smb_fname)
583 int result = -1;
584 struct ceph_statx stx;
586 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
588 if (smb_fname->stream_name) {
589 errno = ENOENT;
590 return result;
593 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
594 SAMBA_STATX_ATTR_MASK, 0);
595 DBG_DEBUG("[CEPH] statx(...) = %d\n", result);
596 if (result < 0) {
597 WRAP_RETURN(result);
598 } else {
599 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
600 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
601 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
602 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
603 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
604 llu(stx.stx_size), llu(stx.stx_blksize),
605 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
606 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
608 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
609 DBG_DEBUG("[CEPH] mode = 0x%x\n", smb_fname->st.st_ex_mode);
610 return result;
613 static int cephwrap_fstat(struct vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
615 int result = -1;
616 struct ceph_statx stx;
618 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
619 result = ceph_fstatx(handle->data, fsp->fh->fd, &stx,
620 SAMBA_STATX_ATTR_MASK, 0);
621 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
622 if (result < 0) {
623 WRAP_RETURN(result);
624 } else {
625 DBG_DEBUG("[CEPH]\tstx = {dev = %llx, ino = %llu, mode = 0x%x, nlink = %llu, "
626 "uid = %d, gid = %d, rdev = %llx, size = %llu, blksize = %llu, "
627 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu, btime = %llu}\n",
628 llu(stx.stx_dev), llu(stx.stx_ino), stx.stx_mode,
629 llu(stx.stx_nlink), stx.stx_uid, stx.stx_gid, llu(stx.stx_rdev),
630 llu(stx.stx_size), llu(stx.stx_blksize),
631 llu(stx.stx_blocks), llu(stx.stx_atime.tv_sec), llu(stx.stx_mtime.tv_sec),
632 llu(stx.stx_ctime.tv_sec), llu(stx.stx_btime.tv_sec));
634 init_stat_ex_from_ceph_statx(sbuf, &stx);
635 DBG_DEBUG("[CEPH] mode = 0x%x\n", sbuf->st_ex_mode);
636 return result;
639 static int cephwrap_lstat(struct vfs_handle_struct *handle,
640 struct smb_filename *smb_fname)
642 int result = -1;
643 struct ceph_statx stx;
645 DBG_DEBUG("[CEPH] lstat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
647 if (smb_fname->stream_name) {
648 errno = ENOENT;
649 return result;
652 result = ceph_statx(handle->data, smb_fname->base_name, &stx,
653 SAMBA_STATX_ATTR_MASK, AT_SYMLINK_NOFOLLOW);
654 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
655 if (result < 0) {
656 WRAP_RETURN(result);
658 init_stat_ex_from_ceph_statx(&smb_fname->st, &stx);
659 return result;
662 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
663 const struct smb_filename *smb_fname,
664 struct smb_file_time *ft)
666 struct ceph_statx stx = { 0 };
667 int result;
668 int mask = 0;
670 if (!null_timespec(ft->atime)) {
671 stx.stx_atime = ft->atime;
672 mask |= CEPH_SETATTR_ATIME;
674 if (!null_timespec(ft->mtime)) {
675 stx.stx_mtime = ft->mtime;
676 mask |= CEPH_SETATTR_MTIME;
678 if (!null_timespec(ft->create_time)) {
679 stx.stx_btime = ft->create_time;
680 mask |= CEPH_SETATTR_BTIME;
683 if (!mask) {
684 return 0;
687 result = ceph_setattrx(handle->data, smb_fname->base_name, &stx, mask, 0);
688 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
689 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
690 ft->create_time.tv_sec, result);
691 return result;
694 #else /* HAVE_CEPH_STATX */
696 static int cephwrap_stat(struct vfs_handle_struct *handle,
697 struct smb_filename *smb_fname)
699 int result = -1;
700 struct stat stbuf;
702 DBG_DEBUG("[CEPH] stat(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
704 if (smb_fname->stream_name) {
705 errno = ENOENT;
706 return result;
709 result = ceph_stat(handle->data, smb_fname->base_name, (struct stat *) &stbuf);
710 DBG_DEBUG("[CEPH] stat(...) = %d\n", result);
711 if (result < 0) {
712 WRAP_RETURN(result);
713 } else {
714 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
715 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
716 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
717 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
718 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
719 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
721 init_stat_ex_from_stat(
722 &smb_fname->st, &stbuf,
723 lp_fake_directory_create_times(SNUM(handle->conn)));
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 stat stbuf;
733 DBG_DEBUG("[CEPH] fstat(%p, %d)\n", handle, fsp->fh->fd);
734 result = ceph_fstat(handle->data, fsp->fh->fd, (struct stat *) &stbuf);
735 DBG_DEBUG("[CEPH] fstat(...) = %d\n", result);
736 if (result < 0) {
737 WRAP_RETURN(result);
738 } else {
739 DBG_DEBUG("[CEPH]\tstbuf = {dev = %llu, ino = %llu, mode = 0x%x, nlink = %llu, "
740 "uid = %d, gid = %d, rdev = %llu, size = %llu, blksize = %llu, "
741 "blocks = %llu, atime = %llu, mtime = %llu, ctime = %llu}\n",
742 llu(stbuf.st_dev), llu(stbuf.st_ino), stbuf.st_mode, llu(stbuf.st_nlink),
743 stbuf.st_uid, stbuf.st_gid, llu(stbuf.st_rdev), llu(stbuf.st_size), llu(stbuf.st_blksize),
744 llu(stbuf.st_blocks), llu(stbuf.st_atime), llu(stbuf.st_mtime), llu(stbuf.st_ctime));
747 init_stat_ex_from_stat(
748 sbuf, &stbuf,
749 lp_fake_directory_create_times(SNUM(handle->conn)));
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 stat stbuf;
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_lstat(handle->data, smb_fname->base_name, &stbuf);
768 DBG_DEBUG("[CEPH] lstat(...) = %d\n", result);
769 if (result < 0) {
770 WRAP_RETURN(result);
772 init_stat_ex_from_stat(
773 &smb_fname->st, &stbuf,
774 lp_fake_directory_create_times(SNUM(handle->conn)));
775 return result;
778 static int cephwrap_ntimes(struct vfs_handle_struct *handle,
779 const struct smb_filename *smb_fname,
780 struct smb_file_time *ft)
782 struct utimbuf buf;
783 int result;
785 if (null_timespec(ft->atime)) {
786 buf.actime = smb_fname->st.st_ex_atime.tv_sec;
787 } else {
788 buf.actime = ft->atime.tv_sec;
790 if (null_timespec(ft->mtime)) {
791 buf.modtime = smb_fname->st.st_ex_mtime.tv_sec;
792 } else {
793 buf.modtime = ft->mtime.tv_sec;
795 if (!null_timespec(ft->create_time)) {
796 set_create_timespec_ea(handle->conn, smb_fname,
797 ft->create_time);
799 if (buf.actime == smb_fname->st.st_ex_atime.tv_sec &&
800 buf.modtime == smb_fname->st.st_ex_mtime.tv_sec) {
801 return 0;
804 result = ceph_utime(handle->data, smb_fname->base_name, &buf);
805 DBG_DEBUG("[CEPH] ntimes(%p, %s, {%ld, %ld, %ld, %ld}) = %d\n", handle, smb_fname_str_dbg(smb_fname),
806 ft->mtime.tv_sec, ft->atime.tv_sec, ft->ctime.tv_sec,
807 ft->create_time.tv_sec, result);
808 return result;
810 #endif /* HAVE_CEPH_STATX */
812 static int cephwrap_unlink(struct vfs_handle_struct *handle,
813 const struct smb_filename *smb_fname)
815 int result = -1;
817 DBG_DEBUG("[CEPH] unlink(%p, %s)\n", handle, smb_fname_str_dbg(smb_fname));
818 if (smb_fname->stream_name) {
819 errno = ENOENT;
820 return result;
822 result = ceph_unlink(handle->data, smb_fname->base_name);
823 DBG_DEBUG("[CEPH] unlink(...) = %d\n", result);
824 WRAP_RETURN(result);
827 static int cephwrap_chmod(struct vfs_handle_struct *handle,
828 const struct smb_filename *smb_fname,
829 mode_t mode)
831 int result;
833 DBG_DEBUG("[CEPH] chmod(%p, %s, %d)\n", handle, smb_fname->base_name, mode);
836 * We need to do this due to the fact that the default POSIX ACL
837 * chmod modifies the ACL *mask* for the group owner, not the
838 * group owner bits directly. JRA.
843 int saved_errno = errno; /* We might get ENOSYS */
844 result = SMB_VFS_CHMOD_ACL(handle->conn,
845 smb_fname,
846 mode);
847 if (result == 0) {
848 return result;
850 /* Error - return the old errno. */
851 errno = saved_errno;
854 result = ceph_chmod(handle->data, smb_fname->base_name, mode);
855 DBG_DEBUG("[CEPH] chmod(...) = %d\n", result);
856 WRAP_RETURN(result);
859 static int cephwrap_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
861 int result;
863 DBG_DEBUG("[CEPH] fchmod(%p, %p, %d)\n", handle, fsp, mode);
866 * We need to do this due to the fact that the default POSIX ACL
867 * chmod modifies the ACL *mask* for the group owner, not the
868 * group owner bits directly. JRA.
872 int saved_errno = errno; /* We might get ENOSYS */
873 if ((result = SMB_VFS_FCHMOD_ACL(fsp, mode)) == 0) {
874 return result;
876 /* Error - return the old errno. */
877 errno = saved_errno;
880 #if defined(HAVE_FCHMOD)
881 result = ceph_fchmod(handle->data, fsp->fh->fd, mode);
882 DBG_DEBUG("[CEPH] fchmod(...) = %d\n", result);
883 WRAP_RETURN(result);
884 #else
885 errno = ENOSYS;
886 #endif
887 return -1;
890 static int cephwrap_chown(struct vfs_handle_struct *handle,
891 const struct smb_filename *smb_fname,
892 uid_t uid,
893 gid_t gid)
895 int result;
896 DBG_DEBUG("[CEPH] chown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
897 result = ceph_chown(handle->data, smb_fname->base_name, uid, gid);
898 DBG_DEBUG("[CEPH] chown(...) = %d\n", result);
899 WRAP_RETURN(result);
902 static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid)
904 int result;
905 #ifdef HAVE_FCHOWN
907 DBG_DEBUG("[CEPH] fchown(%p, %p, %d, %d)\n", handle, fsp, uid, gid);
908 result = ceph_fchown(handle->data, fsp->fh->fd, uid, gid);
909 DBG_DEBUG("[CEPH] fchown(...) = %d\n", result);
910 WRAP_RETURN(result);
911 #else
912 errno = ENOSYS;
913 result = -1;
914 #endif
915 return result;
918 static int cephwrap_lchown(struct vfs_handle_struct *handle,
919 const struct smb_filename *smb_fname,
920 uid_t uid,
921 gid_t gid)
923 int result;
924 DBG_DEBUG("[CEPH] lchown(%p, %s, %d, %d)\n", handle, smb_fname->base_name, uid, gid);
925 result = ceph_lchown(handle->data, smb_fname->base_name, uid, gid);
926 DBG_DEBUG("[CEPH] lchown(...) = %d\n", result);
927 WRAP_RETURN(result);
930 static int cephwrap_chdir(struct vfs_handle_struct *handle, const char *path)
932 int result = -1;
933 DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, path);
935 * If the path is just / use chdir because Ceph is below / and
936 * cannot deal with changing directory above its mount point
938 if (path && !strcmp(path, "/"))
939 return chdir(path);
941 result = ceph_chdir(handle->data, path);
942 DBG_DEBUG("[CEPH] chdir(...) = %d\n", result);
943 WRAP_RETURN(result);
946 static char *cephwrap_getwd(struct vfs_handle_struct *handle)
948 const char *cwd = ceph_getcwd(handle->data);
949 DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd);
950 return SMB_STRDUP(cwd);
953 static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
955 off_t space_to_write;
956 uint64_t space_avail;
957 uint64_t bsize,dfree,dsize;
958 int ret;
959 NTSTATUS status;
960 SMB_STRUCT_STAT *pst;
962 status = vfs_stat_fsp(fsp);
963 if (!NT_STATUS_IS_OK(status)) {
964 return -1;
966 pst = &fsp->fsp_name->st;
968 #ifdef S_ISFIFO
969 if (S_ISFIFO(pst->st_ex_mode))
970 return 0;
971 #endif
973 if (pst->st_ex_size == len)
974 return 0;
976 /* Shrink - just ftruncate. */
977 if (pst->st_ex_size > len)
978 return ftruncate(fsp->fh->fd, len);
980 space_to_write = len - pst->st_ex_size;
982 /* for allocation try fallocate first. This can fail on some
983 platforms e.g. when the filesystem doesn't support it and no
984 emulation is being done by the libc (like on AIX with JFS1). In that
985 case we do our own emulation. fallocate implementations can
986 return ENOTSUP or EINVAL in cases like that. */
987 ret = SMB_VFS_FALLOCATE(fsp, 0, pst->st_ex_size, space_to_write);
988 if (ret == -1 && errno == ENOSPC) {
989 return -1;
991 if (ret == 0) {
992 return 0;
994 DEBUG(10,("[CEPH] strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
995 "error %d. Falling back to slow manual allocation\n", errno));
997 /* available disk space is enough or not? */
998 space_avail =
999 get_dfree_info(fsp->conn, fsp->fsp_name, &bsize, &dfree, &dsize);
1000 /* space_avail is 1k blocks */
1001 if (space_avail == (uint64_t)-1 ||
1002 ((uint64_t)space_to_write/1024 > space_avail) ) {
1003 errno = ENOSPC;
1004 return -1;
1007 /* Write out the real space on disk. */
1008 return vfs_slow_fallocate(fsp, pst->st_ex_size, space_to_write);
1011 static int cephwrap_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len)
1013 int result = -1;
1014 SMB_STRUCT_STAT st;
1015 char c = 0;
1016 off_t currpos;
1018 DBG_DEBUG("[CEPH] ftruncate(%p, %p, %llu\n", handle, fsp, llu(len));
1020 if (lp_strict_allocate(SNUM(fsp->conn))) {
1021 result = strict_allocate_ftruncate(handle, fsp, len);
1022 return result;
1025 /* we used to just check HAVE_FTRUNCATE_EXTEND and only use
1026 sys_ftruncate if the system supports it. Then I discovered that
1027 you can have some filesystems that support ftruncate
1028 expansion and some that don't! On Linux fat can't do
1029 ftruncate extend but ext2 can. */
1031 result = ceph_ftruncate(handle->data, fsp->fh->fd, len);
1032 if (result == 0)
1033 goto done;
1035 /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
1036 extend a file with ftruncate. Provide alternate implementation
1037 for this */
1038 currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR);
1039 if (currpos == -1) {
1040 goto done;
1043 /* Do an fstat to see if the file is longer than the requested
1044 size in which case the ftruncate above should have
1045 succeeded or shorter, in which case seek to len - 1 and
1046 write 1 byte of zero */
1047 if (SMB_VFS_FSTAT(fsp, &st) == -1) {
1048 goto done;
1051 #ifdef S_ISFIFO
1052 if (S_ISFIFO(st.st_ex_mode)) {
1053 result = 0;
1054 goto done;
1056 #endif
1058 if (st.st_ex_size == len) {
1059 result = 0;
1060 goto done;
1063 if (st.st_ex_size > len) {
1064 /* the sys_ftruncate should have worked */
1065 goto done;
1068 if (SMB_VFS_LSEEK(fsp, len-1, SEEK_SET) != len -1)
1069 goto done;
1071 if (SMB_VFS_WRITE(fsp, &c, 1)!=1)
1072 goto done;
1074 /* Seek to where we were */
1075 if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos)
1076 goto done;
1077 result = 0;
1079 done:
1081 return result;
1084 static bool cephwrap_lock(struct vfs_handle_struct *handle, files_struct *fsp, int op, off_t offset, off_t count, int type)
1086 DBG_DEBUG("[CEPH] lock\n");
1087 return true;
1090 static int cephwrap_kernel_flock(struct vfs_handle_struct *handle, files_struct *fsp,
1091 uint32_t share_mode, uint32_t access_mask)
1093 DBG_DEBUG("[CEPH] kernel_flock\n");
1095 * We must return zero here and pretend all is good.
1096 * One day we might have this in CEPH.
1098 return 0;
1101 static bool cephwrap_getlock(struct vfs_handle_struct *handle, files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid)
1103 DBG_DEBUG("[CEPH] getlock returning false and errno=0\n");
1105 errno = 0;
1106 return false;
1110 * We cannot let this fall through to the default, because the file might only
1111 * be accessible from libceph (which is a user-space client) but the fd might
1112 * be for some file the kernel knows about.
1114 static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struct *fsp,
1115 int leasetype)
1117 int result = -1;
1119 DBG_DEBUG("[CEPH] linux_setlease\n");
1120 errno = ENOSYS;
1121 return result;
1124 static int cephwrap_symlink(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath)
1126 int result = -1;
1127 DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle, oldpath, newpath);
1128 result = ceph_symlink(handle->data, oldpath, newpath);
1129 DBG_DEBUG("[CEPH] symlink(...) = %d\n", result);
1130 WRAP_RETURN(result);
1133 static int cephwrap_readlink(struct vfs_handle_struct *handle, const char *path, char *buf, size_t bufsiz)
1135 int result = -1;
1136 DBG_DEBUG("[CEPH] readlink(%p, %s, %p, %llu)\n", handle, path, buf, llu(bufsiz));
1137 result = ceph_readlink(handle->data, path, buf, bufsiz);
1138 DBG_DEBUG("[CEPH] readlink(...) = %d\n", result);
1139 WRAP_RETURN(result);
1142 static int cephwrap_link(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath)
1144 int result = -1;
1145 DBG_DEBUG("[CEPH] link(%p, %s, %s)\n", handle, oldpath, newpath);
1146 result = ceph_link(handle->data, oldpath, newpath);
1147 DBG_DEBUG("[CEPH] link(...) = %d\n", result);
1148 WRAP_RETURN(result);
1151 static int cephwrap_mknod(struct vfs_handle_struct *handle, const char *pathname, mode_t mode, SMB_DEV_T dev)
1153 int result = -1;
1154 DBG_DEBUG("[CEPH] mknod(%p, %s)\n", handle, pathname);
1155 result = ceph_mknod(handle->data, pathname, mode, dev);
1156 DBG_DEBUG("[CEPH] mknod(...) = %d\n", result);
1157 WRAP_RETURN(result);
1161 * This is a simple version of real-path ... a better version is needed to
1162 * ask libceph about symbolic links.
1164 static char *cephwrap_realpath(struct vfs_handle_struct *handle, const char *path)
1166 char *result;
1167 size_t len = strlen(path);
1169 result = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
1170 if (len && (path[0] == '/')) {
1171 int r = asprintf(&result, "%s", path);
1172 if (r < 0) return NULL;
1173 } else if ((len >= 2) && (path[0] == '.') && (path[1] == '/')) {
1174 if (len == 2) {
1175 int r = asprintf(&result, "%s",
1176 handle->conn->connectpath);
1177 if (r < 0) return NULL;
1178 } else {
1179 int r = asprintf(&result, "%s/%s",
1180 handle->conn->connectpath, &path[2]);
1181 if (r < 0) return NULL;
1183 } else {
1184 int r = asprintf(&result, "%s/%s",
1185 handle->conn->connectpath, path);
1186 if (r < 0) return NULL;
1188 DBG_DEBUG("[CEPH] realpath(%p, %s) = %s\n", handle, path, result);
1189 return result;
1192 static int cephwrap_chflags(struct vfs_handle_struct *handle, const char *path,
1193 unsigned int flags)
1195 errno = ENOSYS;
1196 return -1;
1199 static int cephwrap_get_real_filename(struct vfs_handle_struct *handle,
1200 const char *path,
1201 const char *name,
1202 TALLOC_CTX *mem_ctx,
1203 char **found_name)
1206 * Don't fall back to get_real_filename so callers can differentiate
1207 * between a full directory scan and an actual case-insensitive stat.
1209 errno = EOPNOTSUPP;
1210 return -1;
1213 static const char *cephwrap_connectpath(struct vfs_handle_struct *handle,
1214 const char *fname)
1216 return handle->conn->connectpath;
1219 /****************************************************************
1220 Extended attribute operations.
1221 *****************************************************************/
1223 static ssize_t cephwrap_getxattr(struct vfs_handle_struct *handle,const char *path, const char *name, void *value, size_t size)
1225 int ret;
1226 DBG_DEBUG("[CEPH] getxattr(%p, %s, %s, %p, %llu)\n", handle, path, name, value, llu(size));
1227 ret = ceph_getxattr(handle->data, path, name, value, size);
1228 DBG_DEBUG("[CEPH] getxattr(...) = %d\n", ret);
1229 if (ret < 0) {
1230 WRAP_RETURN(ret);
1231 } else {
1232 return (ssize_t)ret;
1236 static ssize_t cephwrap_fgetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, void *value, size_t size)
1238 int ret;
1239 DBG_DEBUG("[CEPH] fgetxattr(%p, %p, %s, %p, %llu)\n", handle, fsp, name, value, llu(size));
1240 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1241 ret = ceph_fgetxattr(handle->data, fsp->fh->fd, name, value, size);
1242 #else
1243 ret = ceph_getxattr(handle->data, fsp->fsp_name->base_name, name, value, size);
1244 #endif
1245 DBG_DEBUG("[CEPH] fgetxattr(...) = %d\n", ret);
1246 if (ret < 0) {
1247 WRAP_RETURN(ret);
1248 } else {
1249 return (ssize_t)ret;
1253 static ssize_t cephwrap_listxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
1255 int ret;
1256 DBG_DEBUG("[CEPH] listxattr(%p, %s, %p, %llu)\n", handle, path, list, llu(size));
1257 ret = ceph_listxattr(handle->data, path, list, size);
1258 DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
1259 if (ret < 0) {
1260 WRAP_RETURN(ret);
1261 } else {
1262 return (ssize_t)ret;
1266 #if 0
1267 static ssize_t cephwrap_llistxattr(struct vfs_handle_struct *handle, const char *path, char *list, size_t size)
1269 int ret;
1270 DBG_DEBUG("[CEPH] llistxattr(%p, %s, %p, %llu)\n", handle, path, list, llu(size));
1271 ret = ceph_llistxattr(handle->data, path, list, size);
1272 DBG_DEBUG("[CEPH] listxattr(...) = %d\n", ret);
1273 if (ret < 0) {
1274 WRAP_RETURN(ret);
1275 } else {
1276 return (ssize_t)ret;
1279 #endif
1281 static ssize_t cephwrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
1283 int ret;
1284 DBG_DEBUG("[CEPH] flistxattr(%p, %p, %s, %llu)\n", handle, fsp, list, llu(size));
1285 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1286 ret = ceph_flistxattr(handle->data, fsp->fh->fd, list, size);
1287 #else
1288 ret = ceph_listxattr(handle->data, fsp->fsp_name->base_name, list, size);
1289 #endif
1290 DBG_DEBUG("[CEPH] flistxattr(...) = %d\n", ret);
1291 if (ret < 0) {
1292 WRAP_RETURN(ret);
1293 } else {
1294 return (ssize_t)ret;
1298 static int cephwrap_removexattr(struct vfs_handle_struct *handle, const char *path, const char *name)
1300 int ret;
1301 DBG_DEBUG("[CEPH] removexattr(%p, %s, %s)\n", handle, path, name);
1302 ret = ceph_removexattr(handle->data, path, name);
1303 DBG_DEBUG("[CEPH] removexattr(...) = %d\n", ret);
1304 WRAP_RETURN(ret);
1307 static int cephwrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
1309 int ret;
1310 DBG_DEBUG("[CEPH] fremovexattr(%p, %p, %s)\n", handle, fsp, name);
1311 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1312 ret = ceph_fremovexattr(handle->data, fsp->fh->fd, name);
1313 #else
1314 ret = ceph_removexattr(handle->data, fsp->fsp_name->base_name, name);
1315 #endif
1316 DBG_DEBUG("[CEPH] fremovexattr(...) = %d\n", ret);
1317 WRAP_RETURN(ret);
1320 static int cephwrap_setxattr(struct vfs_handle_struct *handle, const char *path, const char *name, const void *value, size_t size, int flags)
1322 int ret;
1323 DBG_DEBUG("[CEPH] setxattr(%p, %s, %s, %p, %llu, %d)\n", handle, path, name, value, llu(size), flags);
1324 ret = ceph_setxattr(handle->data, path, name, value, size, flags);
1325 DBG_DEBUG("[CEPH] setxattr(...) = %d\n", ret);
1326 WRAP_RETURN(ret);
1329 static int cephwrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
1331 int ret;
1332 DBG_DEBUG("[CEPH] fsetxattr(%p, %p, %s, %p, %llu, %d)\n", handle, fsp, name, value, llu(size), flags);
1333 #if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(0, 94, 0)
1334 ret = ceph_fsetxattr(handle->data, fsp->fh->fd,
1335 name, value, size, flags);
1336 #else
1337 ret = ceph_setxattr(handle->data, fsp->fsp_name->base_name, name, value, size, flags);
1338 #endif
1339 DBG_DEBUG("[CEPH] fsetxattr(...) = %d\n", ret);
1340 WRAP_RETURN(ret);
1343 static bool cephwrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
1347 * We do not support AIO yet.
1350 DBG_DEBUG("[CEPH] cephwrap_aio_force(%p, %p) = false (errno = ENOTSUP)\n", handle, fsp);
1351 errno = ENOTSUP;
1352 return false;
1355 static struct vfs_fn_pointers ceph_fns = {
1356 /* Disk operations */
1358 .connect_fn = cephwrap_connect,
1359 .disconnect_fn = cephwrap_disconnect,
1360 .disk_free_fn = cephwrap_disk_free,
1361 .get_quota_fn = cephwrap_get_quota,
1362 .set_quota_fn = cephwrap_set_quota,
1363 .statvfs_fn = cephwrap_statvfs,
1365 /* Directory operations */
1367 .opendir_fn = cephwrap_opendir,
1368 .fdopendir_fn = cephwrap_fdopendir,
1369 .readdir_fn = cephwrap_readdir,
1370 .seekdir_fn = cephwrap_seekdir,
1371 .telldir_fn = cephwrap_telldir,
1372 .rewind_dir_fn = cephwrap_rewinddir,
1373 .mkdir_fn = cephwrap_mkdir,
1374 .rmdir_fn = cephwrap_rmdir,
1375 .closedir_fn = cephwrap_closedir,
1377 /* File operations */
1379 .open_fn = cephwrap_open,
1380 .close_fn = cephwrap_close,
1381 .read_fn = cephwrap_read,
1382 .pread_fn = cephwrap_pread,
1383 .write_fn = cephwrap_write,
1384 .pwrite_fn = cephwrap_pwrite,
1385 .lseek_fn = cephwrap_lseek,
1386 .sendfile_fn = cephwrap_sendfile,
1387 .recvfile_fn = cephwrap_recvfile,
1388 .rename_fn = cephwrap_rename,
1389 .fsync_fn = cephwrap_fsync,
1390 .stat_fn = cephwrap_stat,
1391 .fstat_fn = cephwrap_fstat,
1392 .lstat_fn = cephwrap_lstat,
1393 .unlink_fn = cephwrap_unlink,
1394 .chmod_fn = cephwrap_chmod,
1395 .fchmod_fn = cephwrap_fchmod,
1396 .chown_fn = cephwrap_chown,
1397 .fchown_fn = cephwrap_fchown,
1398 .lchown_fn = cephwrap_lchown,
1399 .chdir_fn = cephwrap_chdir,
1400 .getwd_fn = cephwrap_getwd,
1401 .ntimes_fn = cephwrap_ntimes,
1402 .ftruncate_fn = cephwrap_ftruncate,
1403 .lock_fn = cephwrap_lock,
1404 .kernel_flock_fn = cephwrap_kernel_flock,
1405 .linux_setlease_fn = cephwrap_linux_setlease,
1406 .getlock_fn = cephwrap_getlock,
1407 .symlink_fn = cephwrap_symlink,
1408 .readlink_fn = cephwrap_readlink,
1409 .link_fn = cephwrap_link,
1410 .mknod_fn = cephwrap_mknod,
1411 .realpath_fn = cephwrap_realpath,
1412 .chflags_fn = cephwrap_chflags,
1413 .get_real_filename_fn = cephwrap_get_real_filename,
1414 .connectpath_fn = cephwrap_connectpath,
1416 /* EA operations. */
1417 .getxattr_fn = cephwrap_getxattr,
1418 .fgetxattr_fn = cephwrap_fgetxattr,
1419 .listxattr_fn = cephwrap_listxattr,
1420 .flistxattr_fn = cephwrap_flistxattr,
1421 .removexattr_fn = cephwrap_removexattr,
1422 .fremovexattr_fn = cephwrap_fremovexattr,
1423 .setxattr_fn = cephwrap_setxattr,
1424 .fsetxattr_fn = cephwrap_fsetxattr,
1426 /* Posix ACL Operations */
1427 .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
1428 .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
1429 .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
1430 .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
1431 .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
1432 .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
1433 .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
1435 /* aio operations */
1436 .aio_force_fn = cephwrap_aio_force,
1439 NTSTATUS vfs_ceph_init(void);
1440 NTSTATUS vfs_ceph_init(void)
1442 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1443 "ceph", &ceph_fns);